adding function to modify existing subnets
[controller.git] / opendaylight / northbound / subnets / src / main / java / org / opendaylight / controller / subnets / northbound / SubnetsNorthboundJAXRS.java
index 05bb5b1dd938ff9208eb5fcda84c6d262e50be33..6869fd5fbea37595c33eec0d2f04c950db5e754a 100644 (file)
@@ -8,7 +8,10 @@
 package org.opendaylight.controller.subnets.northbound;
 
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
 
+import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -20,6 +23,7 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
+import javax.xml.bind.JAXBElement;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
@@ -27,6 +31,7 @@ import org.codehaus.enunciate.jaxrs.TypeHint;
 import org.opendaylight.controller.northbound.commons.RestMessages;
 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
 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;
@@ -55,10 +60,10 @@ public class SubnetsNorthboundJAXRS {
 
     /**
      * List all the subnets in a given container
-     * 
+     *
      * @param containerName
      *            container in which we want to query the subnets
-     * 
+     *
      * @return a List of SubnetConfig
      */
     @Path("/{containerName}")
@@ -86,12 +91,12 @@ public class SubnetsNorthboundJAXRS {
 
     /**
      * List the configuration of a subnet in a given container
-     * 
+     *
      * @param containerName
      *            container in which we want to query the subnet
      * @param subnetName
      *            of the subnet being queried
-     * 
+     *
      * @return a SubnetConfig
      */
     @Path("/{containerName}/{subnetName}")
@@ -128,8 +133,8 @@ public class SubnetsNorthboundJAXRS {
     }
 
     /**
-     * Add/Update a subnet to a container
-     * 
+     * Add a subnet to a container
+     *
      * @param containerName
      *            container in which we want to add/update the subnet
      * @param subnetName
@@ -137,14 +142,13 @@ public class SubnetsNorthboundJAXRS {
      * @param subnet
      *            pair default gateway IP/mask that identify the subnet being
      *            added modified
-     * 
+     *
      */
     @Path("/{containerName}/{subnetName}")
     @POST
     @StatusCodes({
-            @ResponseCode(code = 404, condition = "The containerName passed was not found"),
             @ResponseCode(code = 404, condition = "Invalid Data passed"),
-            @ResponseCode(code = 201, condition = "Subnet added/modified"),
+            @ResponseCode(code = 201, condition = "Subnet added"),
             @ResponseCode(code = 500, condition = "Addition of subnet failed") })
     public Response addSubnet(@PathParam("containerName") String containerName,
             @PathParam("subnetName") String subnetName,
@@ -183,12 +187,12 @@ public class SubnetsNorthboundJAXRS {
 
     /**
      * Delete a subnet from a container
-     * 
+     *
      * @param containerName
      *            container in which we want to delete the subnet by name
      * @param subnetName
      *            of the subnet to be remove.
-     * 
+     *
      */
     @Path("/{containerName}/{subnetName}")
     @DELETE
@@ -224,57 +228,139 @@ public class SubnetsNorthboundJAXRS {
         throw new InternalServerErrorException(status.getDescription());
     }
 
+    /**
+     * Modify a subnet. For now only changing the port list is allowed.
+     *
+     * @param containerName
+     *            Name of the Container
+     * @param name
+     *            Name of the SubnetConfig to be modified
+     * @param subnetConfigData
+     *            the {@link SubnetConfig} structure in JSON passed as a POST
+     *            parameter
+     * @return If the operation is successful or not
+     */
+    @Path("/{containerName}/{subnetName}/modify")
+    @POST
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
+            @ResponseCode(code = 202, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Invalid request, i.e., requested changing the subnet name"),
+            @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
+            @ResponseCode(code = 500, condition = "Internal server error")})
+    public Response modifySubnet(@PathParam("containerName") String containerName,
+                                 @PathParam("subnetName") String name,
+                                 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
+
+        if (!NorthboundUtils.isAuthorized(getUserName(), containerName,
+                                          Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                "User is not authorized to perform this operation on container " + containerName);
+        }
+
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class,
+                                                                                  containerName, this);
+        if (switchManager == null) {
+            throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
+        }
+
+        SubnetConfig subnetConf = subnetConfigData.getValue();
+        SubnetConfig existingConf = switchManager.getSubnetConfig(name);
+
+        boolean successful = true;
+
+        // make sure that the name matches an existing subnet and we're not
+        // changing the name or subnet IP/mask
+        if (existingConf == null){
+            // don't have a subnet by that name
+            return Response.status(Response.Status.NOT_FOUND).build();
+
+        }else if( !existingConf.getName().equals(subnetConf.getName())
+            || !existingConf.getSubnet().equals(subnetConf.getSubnet())) {
+            // can't change the name of a subnet
+            return Response.status(Response.Status.BAD_REQUEST).build();
+
+        }else{
+            // create a set for fast lookups
+            Set<String> newPorts = new HashSet<String>(subnetConf.getNodePorts());
+
+            // go through the current ports and (1) remove ports that aren't
+            // there anymore and (2) remove ports that are still there from the
+            // set of ports to add
+            for(String s : existingConf.getNodePorts()){
+                if(newPorts.contains(s)){
+                    newPorts.remove(s);
+                }else{
+                    Status st = switchManager.removePortsFromSubnet(name, s);
+                    successful = successful && st.isSuccess();
+                }
+            }
+
+            // add any remaining ports
+            for(String s : newPorts){
+                Status st = switchManager.addPortsToSubnet(name, s);
+                successful = successful && st.isSuccess();
+            }
+        }
+
+        if(successful){
+            return Response.status(Response.Status.ACCEPTED).build();
+        }else{
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+        }
+    }
+
     /*
-     * 
+     *
      * Add or remove switch ports to a subnet POST subnets/green/sw
-     * 
+     *
      * @param model
-     * 
+     *
      * @param containerName
-     * 
+     *
      * @param name
-     * 
+     *
      * @param subnet: the subnet name name
-     * 
+     *
      * @param switchports: datapath ID/port list =>
      * xx:xx:xx:xx:xx:xx:xx:xx/a,b,c-m,r-t,y
-     * 
+     *
      * @return
-     * 
+     *
      * @RequestMapping(value = "/{containerName}/{name}", method =
      * RequestMethod.POST)
-     * 
+     *
      * public View addSwitchports(Map<String, Object> model,
-     * 
+     *
      * @PathVariable(value = "containerName") String containerName,
-     * 
+     *
      * @PathVariable(value = "name") String name,
-     * 
+     *
      * @RequestParam(value = "nodeports") String nodePorts,
-     * 
+     *
      * @RequestParam(value = "action") String action) {
-     * 
+     *
      * checkDefaultDisabled(containerName); ISwitchManager switchManager = null;
      * try { BundleContext bCtx = FrameworkUtil.getBundle(this.getClass())
      * .getBundleContext();
-     * 
+     *
      * ServiceReference[] services = bCtx.getServiceReferences(
      * ISwitchManager.class.getName(), "(containerName=" + containerName + ")");
-     * 
+     *
      * if (services != null) { switchManager = (ISwitchManager)
      * bCtx.getService(services[0]); logger.debug("Switch manager reference is:"
      * + switchManager); } } catch (Exception e) {
      * logger.error("Switch Manager reference is NULL"); }
-     * 
+     *
      * checkContainerExists(switchManager);
-     * 
+     *
      * String ret; if (action.equals("add")) { ret =
      * switchManager.addPortsToSubnet(name, nodePorts); } else if
      * (action.equals("remove")) { ret =
      * switchManager.removePortsFromSubnet(name, nodePorts); } else { throw new
      * UnsupportedMediaTypeException(RestMessages.UNKNOWNACTION .toString() +
      * ": " + action); }
-     * 
+     *
      * return returnViewOrThrowConflicEx(model, ret); }
      */
 }