X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fnorthbound%2Fflowprogrammer%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fflowprogrammer%2Fnorthbound%2FFlowProgrammerNorthbound.java;h=4928ddef3b0296b8525531791dfe4272064dfaa1;hb=011123a270b7126d8c49191a88e48f15106bb4c8;hp=ed3abde0ab22bc84049f3f8787436d5a775a8fda;hpb=f5bc1a15da8600a9bc6dc7829792566cf0e72e7c;p=controller.git 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 ed3abde0ab..4928ddef3b 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 @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -20,9 +19,10 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.xml.bind.JAXBElement; +import javax.ws.rs.core.SecurityContext; import org.codehaus.enunciate.jaxrs.ResponseCode; import org.codehaus.enunciate.jaxrs.StatusCodes; @@ -32,10 +32,13 @@ 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; import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; +import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException; +import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils; +import org.opendaylight.controller.sal.authorization.Privilege; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.ServiceHelper; @@ -43,28 +46,38 @@ import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.switchmanager.ISwitchManager; /** - * Flow Configuration Northbound API + * Flow Configuration Northbound API provides capabilities to program flows. * - *

+ *
+ *
* Authentication scheme : HTTP Basic
* Authentication realm : opendaylight
* Transport : HTTP and HTTPS
*
- * HTTPS Authentication is disabled by default. Administrator can enable it in tomcat-server.xml after adding - * a proper keystore / SSL certificate from a trusted authority.
- * More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration + * HTTPS Authentication is disabled by default. * */ @Path("/") public class FlowProgrammerNorthbound { - private IForwardingRulesManager getForwardingRulesManagerService( - String containerName) { - IContainerManager containerManager = (IContainerManager) ServiceHelper - .getGlobalInstance(IContainerManager.class, this); + private String username; + + @Context + public void setSecurityContext(SecurityContext context) { + if (context != null && context.getUserPrincipal() != null) { + username = context.getUserPrincipal().getName(); + } + } + + protected String getUserName() { + return username; + } + + private IForwardingRulesManager getForwardingRulesManagerService(String containerName) { + IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance( + IContainerManager.class, this); if (containerManager == null) { - throw new ServiceUnavailableException("Container " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Container " + RestMessages.SERVICEUNAVAILABLE.toString()); } boolean found = false; @@ -76,28 +89,24 @@ public class FlowProgrammerNorthbound { } if (found == false) { - throw new ResourceNotFoundException(containerName + " " - + RestMessages.NOCONTAINER.toString()); + throw new ResourceNotFoundException(containerName + " " + RestMessages.NOCONTAINER.toString()); } - IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper - .getInstance(IForwardingRulesManager.class, containerName, this); + IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance( + IForwardingRulesManager.class, containerName, this); if (frm == null) { - throw new ServiceUnavailableException("Flow Programmer " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Flow Programmer " + RestMessages.SERVICEUNAVAILABLE.toString()); } return frm; } - private List getStaticFlowsInternal(String containerName, - Node node) { + private List getStaticFlowsInternal(String containerName, Node node) { IForwardingRulesManager frm = getForwardingRulesManagerService(containerName); if (frm == null) { - throw new ServiceUnavailableException("Flow Programmer " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Flow Programmer " + RestMessages.SERVICEUNAVAILABLE.toString()); } List flows = new ArrayList(); @@ -107,17 +116,14 @@ public class FlowProgrammerNorthbound { flows.add(flow); } } else { - ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance( - ISwitchManager.class, containerName, this); + ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this); if (sm == null) { - throw new ServiceUnavailableException("Switch Manager " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Switch Manager " + RestMessages.SERVICEUNAVAILABLE.toString()); } if (!sm.getNodes().contains(node)) { - throw new ResourceNotFoundException(node.toString() + " : " - + RestMessages.NONODE.toString()); + throw new ResourceNotFoundException(node.toString() + " : " + RestMessages.NONODE.toString()); } for (FlowConfig flow : frm.getStaticFlows(node)) { @@ -130,19 +136,71 @@ 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 + * @param containerName + * Name of the Container (Eg. 'default') + * @return List of flows configured on a given container + * + *
+     *
+     * Example:
+     *
+     * Request URL:
+     * http://localhost:8080/controller/nb/v2/flowprogrammer/default
+     *
+     * Response body 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</id>
+     *                      <type>OF</type>
+     *               </node>
+     *               <ingressPort>1</ingressPort>
+     *               <priority>500</priority>
+     *               <etherType>0x800</etherType>
+     *               <nwSrc>9.9.1.1</nwSrc>
+     *               <actions>OUTPUT=2</actions>
+     *        </flowConfig>
+     * </list>
+     *
+     * Response body in JSON:
+     * {
+     *   "flowConfig": [
+     *      {
+     *         "installInHw": "true",
+     *         "name": "flow1",
+     *         "node": {
+     *            "type": "OF",
+     *            "id": "00:00:00:00:00:00:00:01"
+     *         },
+     *         "ingressPort": "1",
+     *         "priority": "500",
+     *         "etherType": "0x800",
+     *         "nwSrc":"9.9.1.1",
+     *         "actions": [
+     *           "OUTPUT=2"
+     *         ]
+     *      }
+     *    ]
+     * }
+     * 
*/ @Path("/{containerName}") @GET - @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @TypeHint(FlowConfigs.class) - @StatusCodes( { - @ResponseCode(code = 200, condition = "Operation successful"), - @ResponseCode(code = 404, condition = "The containerName is not found"), - @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") }) - public FlowConfigs getStaticFlows( - @PathParam("containerName") String containerName) { + @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(@PathParam("containerName") String containerName) { + if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) { + throw new UnauthorizedException("User is not authorized to perform this operation on container " + + containerName); + } + List flowConfigs = getStaticFlowsInternal(containerName, null); return new FlowConfigs(flowConfigs); } @@ -150,62 +208,157 @@ 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". - * @param nodeType Type of the node being programmed - * @param nodeId Node Identifier - * @return List of configured flows configured on a Node in a container + * @param containerName + * Name of the Container (Eg. 'default') + * @param nodeType + * Type of the node being programmed (Eg. 'OF') + * @param nodeId + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') + * @return List of flows configured on a Node in a container + * + *
+     *
+     * Example:
+     *
+     * Request URL:
+     * http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01
+     *
+     * Response body 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</id>
+     *                      <type>OF</type>
+     *               </node>
+     *               <ingressPort>1</ingressPort>
+     *               <priority>500</priority>
+     *               <etherType>0x800</etherType>
+     *               <nwSrc>9.9.1.1</nwSrc>
+     *               <actions>OUTPUT=2</actions>
+     *        </flowConfig>
+     * </list>
+     *
+    * Response body in JSON:
+     * {
+     *   "flowConfig": [
+     *      {
+     *         "installInHw": "true",
+     *         "name": "flow1",
+     *         "node": {
+     *            "type": "OF",
+     *            "id": "00:00:00:00:00:00:00:01"
+     *         },
+     *         "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 }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @TypeHint(FlowConfigs.class) - @StatusCodes( { - @ResponseCode(code = 200, condition = "Operation successful"), - @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( - @PathParam("containerName") String containerName, - @PathParam("nodeType") String nodeType, - @PathParam("nodeId") String nodeId) { + @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(@PathParam("containerName") String containerName, + @PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId) { + if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) { + throw new UnauthorizedException("User is not authorized to perform this operation on container " + + containerName); + } Node node = Node.fromString(nodeType, nodeId); if (node == null) { - throw new ResourceNotFoundException(nodeId + " : " - + RestMessages.NONODE.toString()); + throw new ResourceNotFoundException(nodeId + " : " + RestMessages.NONODE.toString()); } List flows = getStaticFlowsInternal(containerName, node); return new FlowConfigs(flows); } /** - * Returns the flow configuration matching a human-readable name and nodeId on a - * given Container. - * - * @param containerName Name of the Container. The Container name - * for the base controller is "default". - * @param nodeType Type of the node being programmed - * @param nodeId Node Identifier - * @param name Human-readable name for the configured flow. + * Returns the flow configuration matching a human-readable name and nodeId + * on a given Container. + * + * @param containerName + * Name of the Container (Eg. 'default') + * @param nodeType + * Type of the node being programmed (Eg. 'OF') + * @param nodeId + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') + * @param name + * Human-readable name for the configured flow (Eg. 'Flow1') * @return Flow configuration matching the name and nodeId on a Container + * + *
+     *
+     * Example:
+     *
+     * Request URL:
+     * http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
+     *
+     * Response body 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</id>
+     *               <type>OF</type>
+     *        </node>
+     *        <ingressPort>1</ingressPort>
+     *        <priority>500</priority>
+     *        <etherType>0x800</etherType>
+     *        <nwSrc>9.9.1.1</nwSrc>
+     *        <actions>OUTPUT=2</actions>
+     * </flowConfig>
+     *
+    * Response body 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}/staticFlow/{name}") @GET - @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @TypeHint(FlowConfig.class) - @StatusCodes( { - @ResponseCode(code = 200, condition = "Operation successful"), - @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( - @PathParam("containerName") String containerName, - @PathParam("nodeType") String nodeType, - @PathParam("nodeId") String nodeId, - @PathParam("name") String name) { + @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(@PathParam("containerName") String containerName, + @PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId, @PathParam("name") String name) { + if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) { + throw new UnauthorizedException("User is not authorized to perform this operation on container " + + containerName); + } IForwardingRulesManager frm = getForwardingRulesManagerService(containerName); if (frm == null) { - throw new ServiceUnavailableException("Flow Programmer " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Flow Programmer " + RestMessages.SERVICEUNAVAILABLE.toString()); } Node node = handleNodeAvailability(containerName, nodeType, nodeId); @@ -219,195 +372,282 @@ public class FlowProgrammerNorthbound { } /** - * Add a flow configuration - * - * @param containerName Name of the Container. The Container name - * for the base controller is "default". - * @param nodeType Type of the node being programmed - * @param nodeId Node Identifier - * @param name Name of the Static Flow configuration - * @param FlowConfig Flow Configuration in JSON or XML format + * Add or Modify a flow configuration. If the flow exists already, it will replace the current flow. + * + * @param containerName + * Name of the Container (Eg. 'default') + * @param nodeType + * Type of the node being programmed (Eg. 'OF') + * @param nodeId + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') + * @param name + * 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:
+     *
+     * Request URL:
+     * http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
+     *
+     * Request body in XML:
+     * <flowConfig>
+     *            <installInHw>true</installInHw>
+     *            <name>flow1</name>
+     *            <node>
+     *                   <id>00:00:00:00:00:00:00:01</id>
+     *                   <type>OF</type>
+     *            </node>
+     *            <ingressPort>1</ingressPort>
+     *            <priority>500</priority>
+     *            <etherType>0x800</etherType>
+     *            <nwSrc>9.9.1.1</nwSrc>
+     *            <actions>OUTPUT=2</actions>
+     * </flowConfig>
+     *
+     * Request body 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 - @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 = 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 = 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( - @PathParam(value = "containerName") String containerName, - @PathParam(value = "name") String name, - @PathParam("nodeType") String nodeType, - @PathParam(value = "nodeId") String nodeId, - @TypeHint(FlowConfig.class) JAXBElement flowConfig) { + @Path("/{containerName}/node/{nodeType}/{nodeId}/staticFlow/{name}") + @PUT + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Static Flow modified successfully"), + @ResponseCode(code = 201, condition = "Flow Config processed successfully"), + @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 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 addOrModifyFlow(@PathParam(value = "containerName") String containerName, + @PathParam(value = "name") String name, @PathParam("nodeType") String nodeType, + @PathParam(value = "nodeId") String nodeId, @TypeHint(FlowConfig.class) FlowConfig flowConfig) { + + if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) { + throw new UnauthorizedException("User is not authorized to perform this operation on container " + + containerName); + } + if (flowConfig.getNode() == null) { + return Response.status(Response.Status.BAD_REQUEST).entity("Invalid Configuration. Node is null or empty") + .build(); + } + handleResourceCongruence(name, flowConfig.getName()); + handleResourceCongruence(nodeType, flowConfig.getNode().getType()); + handleResourceCongruence(nodeId, flowConfig.getNode().getID() == null ? null : flowConfig.getNode().getNodeIDString()); handleDefaultDisabled(containerName); IForwardingRulesManager frm = getForwardingRulesManagerService(containerName); if (frm == null) { - throw new ServiceUnavailableException("Flow Programmer " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Flow Programmer " + RestMessages.SERVICEUNAVAILABLE.toString()); } Node node = handleNodeAvailability(containerName, nodeType, nodeId); + Status status; FlowConfig staticFlow = frm.getStaticFlow(name, node); - if (staticFlow != null) { - throw new ResourceConflictException(name + " already exists." - + RestMessages.RESOURCECONFLICT.toString()); - } - Status status = frm.addStaticFlow(flowConfig.getValue(), false); - if (status.isSuccess()) { - return Response.status(Response.Status.CREATED).build(); + if (staticFlow == null) { + status = frm.addStaticFlow(flowConfig); + if(status.isSuccess()){ + NorthboundUtils.auditlog("Flow Entry", username, "added", + name + " on Node " + NorthboundUtils.getNodeDesc(node, containerName, this), containerName); + return Response.status(Response.Status.CREATED).entity("Success").build(); + } + } else { + status = frm.modifyStaticFlow(flowConfig); + if(status.isSuccess()){ + NorthboundUtils.auditlog("Flow Entry", username, "updated", + name + " on Node " + NorthboundUtils.getNodeDesc(node, containerName, this), containerName); + return NorthboundUtils.getResponse(status); + } } - 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". - * @param nodeType Type of the node being programmed - * @param nodeId Node Identifier - * @param name Name of the Static Flow configuration + * @param containerName + * Name of the Container (Eg. 'default') + * @param nodeType + * Type of the node being programmed (Eg. 'OF') + * @param nodeId + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') + * @param name + * 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/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
+     *
+     * 
*/ - @Path("/{containerName}/{nodeType}/{nodeId}/{name}") + @Path("/{containerName}/node/{nodeType}/{nodeId}/staticFlow/{name}") @DELETE - @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @StatusCodes( { - @ResponseCode(code = 200, condition = "Flow Config deleted successfully"), - @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 = 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( - @PathParam(value = "containerName") String containerName, - @PathParam(value = "name") String name, - @PathParam("nodeType") String nodeType, + @StatusCodes({ + @ResponseCode(code = 204, 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 = "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(@PathParam(value = "containerName") String containerName, + @PathParam(value = "name") String name, @PathParam("nodeType") String nodeType, @PathParam(value = "nodeId") String nodeId) { + if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) { + throw new UnauthorizedException("User is not authorized to perform this operation on container " + + containerName); + } handleDefaultDisabled(containerName); IForwardingRulesManager frm = getForwardingRulesManagerService(containerName); if (frm == null) { - throw new ServiceUnavailableException("Flow Programmer " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Flow Programmer " + RestMessages.SERVICEUNAVAILABLE.toString()); } Node node = handleNodeAvailability(containerName, nodeType, nodeId); FlowConfig staticFlow = frm.getStaticFlow(name, node); if (staticFlow == null) { - throw new ResourceNotFoundException(name + " : " - + RestMessages.NOFLOW.toString()); + throw new ResourceNotFoundException(name + " : " + RestMessages.NOFLOW.toString()); } Status status = frm.removeStaticFlow(name, node); if (status.isSuccess()) { - return Response.ok().build(); + NorthboundUtils.auditlog("Flow Entry", username, "removed", + name + " from Node " + NorthboundUtils.getNodeDesc(node, containerName, this), containerName); + return Response.noContent().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". - * @param nodeType Type of the node being programmed - * @param nodeId Node Identifier - * @param name Name of the Static Flow configuration + * @param containerName + * Name of the Container (Eg. 'default') + * @param nodeType + * Type of the node being programmed (Eg. 'OF') + * @param nodeId + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') + * @param name + * 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/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
+     *
+     * 
*/ - - @Path("/{containerName}/{nodeType}/{nodeId}/{name}") - @PUT - @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @StatusCodes( { - @ResponseCode(code = 200, condition = "Flow Config deleted successfully"), - @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 = 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( - @PathParam(value = "containerName") String containerName, - @PathParam("nodeType") String nodeType, - @PathParam(value = "nodeId") String nodeId, + @Path("/{containerName}/node/{nodeType}/{nodeId}/staticFlow/{name}") + @POST + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @StatusCodes({ + @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 = "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(@PathParam(value = "containerName") String containerName, + @PathParam("nodeType") String nodeType, @PathParam(value = "nodeId") String nodeId, @PathParam(value = "name") String name) { + if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) { + throw new UnauthorizedException("User is not authorized to perform this operation on container " + + containerName); + } + handleDefaultDisabled(containerName); IForwardingRulesManager frm = getForwardingRulesManagerService(containerName); if (frm == null) { - throw new ServiceUnavailableException("Flow Programmer " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Flow Programmer " + RestMessages.SERVICEUNAVAILABLE.toString()); } Node node = handleNodeAvailability(containerName, nodeType, nodeId); FlowConfig staticFlow = frm.getStaticFlow(name, node); if (staticFlow == null) { - throw new ResourceNotFoundException(name + " : " - + RestMessages.NOFLOW.toString()); + throw new ResourceNotFoundException(name + " : " + RestMessages.NOFLOW.toString()); } Status status = frm.toggleStaticFlowStatus(staticFlow); if (status.isSuccess()) { - return Response.ok().build(); + NorthboundUtils.auditlog("Flow Entry", username, "toggled", + name + " on Node " + NorthboundUtils.getNodeDesc(node, containerName, this), containerName); } - throw new InternalServerErrorException(status.getDescription()); + return NorthboundUtils.getResponse(status); } - private Node handleNodeAvailability(String containerName, String nodeType, - String nodeId) { + private Node handleNodeAvailability(String containerName, String nodeType, String nodeId) { Node node = Node.fromString(nodeType, nodeId); if (node == null) { - throw new ResourceNotFoundException(nodeId + " : " - + RestMessages.NONODE.toString()); + throw new ResourceNotFoundException(nodeId + " : " + RestMessages.NONODE.toString()); } - ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance( - ISwitchManager.class, containerName, this); + ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this); if (sm == null) { - throw new ServiceUnavailableException("Switch Manager " - + RestMessages.SERVICEUNAVAILABLE.toString()); + throw new ServiceUnavailableException("Switch Manager " + RestMessages.SERVICEUNAVAILABLE.toString()); } if (!sm.getNodes().contains(node)) { - throw new ResourceNotFoundException(node.toString() + " : " - + RestMessages.NONODE.toString()); + throw new ResourceNotFoundException(node.toString() + " : " + RestMessages.NONODE.toString()); } return node; } private void handleDefaultDisabled(String containerName) { - IContainerManager containerManager = (IContainerManager) ServiceHelper - .getGlobalInstance(IContainerManager.class, this); + IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance( + IContainerManager.class, this); if (containerManager == null) { - throw new InternalServerErrorException(RestMessages.INTERNALERROR - .toString()); + throw new InternalServerErrorException(RestMessages.INTERNALERROR.toString()); } - if (containerName.equals(GlobalConstants.DEFAULT.toString()) - && containerManager.hasNonDefaultContainer()) { - throw new NotAcceptableException(RestMessages.DEFAULTDISABLED - .toString()); + if (containerName.equals(GlobalConstants.DEFAULT.toString()) && containerManager.hasNonDefaultContainer()) { + throw new NotAcceptableException(RestMessages.DEFAULTDISABLED.toString()); + } + } + + private void handleResourceCongruence(String resource, String configured) { + if (!resource.equals(configured)) { + throw new MethodNotAllowedException("Path's resource name conflicts with payload's resource name"); } }