Move adsal into its own subdirectory.
[controller.git] / opendaylight / adsal / samples / northbound / loadbalancer / src / main / java / org / opendaylight / controller / samples / loadbalancer / northbound / LoadBalancerNorthbound.java
diff --git a/opendaylight/adsal/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthbound.java b/opendaylight/adsal/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthbound.java
new file mode 100644 (file)
index 0000000..2734c09
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.loadbalancer.northbound;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+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.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+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.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.UnsupportedMediaTypeException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.samples.loadbalancer.IConfigManager;
+
+/**
+ * This class exposes North bound REST APIs for the Load Balancer Service.
+ * Following APIs are exposed by the Load Balancer Service:
+ *
+ * Data retrieval REST APIs::
+ *      1. Get details of all existing pools
+ *              Type : GET
+ *              URI : /one/nb/v2/lb/{container-name}/
+ *      NOTE: Current implementation of the opendaylight usage 'default' as a container-name
+ *      e.g : http://localhost:8080/one/nb/v2/lb/default will give you list of all the pools
+ *
+ *      2. Get details of all the existing VIPs
+ *              Type : GET
+ *              URI:  /one/nb/v2/lb/{container-name}/vips
+ *
+ * Pool related REST APIs::
+ *      1. Create Pool :
+ *              Type : POST
+ *              URI : /one/nb/v2/lb/{container-name}/create/pool
+ *              Request body :
+ *                      {
+ *                              "name":"",
+ *                              "lbmethod":""
+ *                      }
+ *              Currently, two load balancing policies are allowed {"roundrobin" and "random" }
+ *
+ *      2. Delete Pool :
+ *              Type : DELETE
+ *              URI : /one/nb/v2/lb/{container-name}/delete/pool/{pool-name}
+ *
+ * VIP related REST APIs::
+ *      1. Create VIP:
+ *              Type : POST
+ *              URI : /one/nb/v2/lb/{container-name}/create/vip
+ *              Request body :
+ *                      {
+ *                              "name":"",
+ *                              "ip":"ip in (xxx.xxx.xxx.xxx) format",
+ *                              "protocol":"TCP/UDP",
+ *                              "port":"any valid port number",
+ *                              "poolname":"" (optional)
+ *                       }
+ *              The pool name is optional and can be set up at a later stage (using the REST API given below).
+ *
+ *      2. Update VIP: Update pool name of the VIP
+ *              Type : PUT
+ *              URI : /one/nb/v2/lb/{container-name}/update/vip
+ *              Request body :
+ *                      {
+ *                              "name":"",
+ *                              "poolname":""
+ *                       }
+ *              Currently, we only allow update of the VIP pool name (if a VIP does not have an attached pool)
+ *              and not of the VIP name itself.
+ *              The specified pool name must already exist. If the specified VIP is already attached to a pool, the update
+ *              will fail.
+ *
+ *      3. Delete VIP :
+ *              Type : DELETE
+ *              URI : /one/nb/v2/lb/{container-name}/delete/vip/{vip-name}
+ *
+ * Pool member related REST APIs::
+ *      1. Create pool member:
+ *              Type : POST
+ *              URI : /one/nb/v2/lb/default/create/poolmember
+ *              Request body :
+ *                      {
+ *                              "name":"",
+ *                              "ip":"ip in (xxx.xxx.xxx.xxx) format",
+ *                              "poolname":"existing pool name"
+ *                       }
+ *
+ *      2. Delete pool member:
+ *              Type : DELETE
+ *              URI : /one/nb/v2/lb/{container-name}/delete/poolmember/{pool-member-name}/{pool-name}
+ *
+ *  NOTE: Property "name" of each individual entity must be unique.
+ *  All the above REST APIs throw appropriate response codes in case of error/success.
+ *  Please consult the respective methods to get details of various response codes.
+ */
+
+@Path("/")
+public class LoadBalancerNorthbound {
+
+    /*
+     * Method returns the Load balancer service instance running within
+     * 'default' container.
+     */
+    private IConfigManager getConfigManagerService(String containerName) {
+        IContainerManager containerManager = (IContainerManager) ServiceHelper
+                .getGlobalInstance(IContainerManager.class, this);
+        if (containerManager == null) {
+            throw new ServiceUnavailableException("Container "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        boolean found = false;
+        List<String> containerNames = containerManager.getContainerNames();
+        for (String cName : containerNames) {
+            if (cName.trim().equalsIgnoreCase(containerName.trim())) {
+                found = true;
+            }
+        }
+
+        if (found == false) {
+            throw new ResourceNotFoundException(containerName + " "
+                    + RestMessages.NOCONTAINER.toString());
+        }
+
+        IConfigManager configManager = (IConfigManager) ServiceHelper.getInstance(
+                        IConfigManager.class, containerName, this);
+
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer"
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        return configManager;
+    }
+
+    @Path("/{containerName}")
+    @GET
+    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Pools.class)
+    @StatusCodes( {
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "Load balancer service is unavailable") })
+    public Pools getAllPools(
+            @PathParam("containerName") String containerName) {
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer "
+                                                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        return new Pools(configManager.getAllPools());
+    }
+
+    @Path("/{containerName}/vips")
+    @GET
+    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(VIPs.class)
+    @StatusCodes( {
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "Load balancer service is unavailable") })
+    public VIPs getAllVIPs(
+            @PathParam("containerName") String containerName) {
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        return new VIPs(configManager.getAllVIPs());
+    }
+
+    @Path("/{containerName}/create/vip")
+    @POST
+    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes( {
+        @ResponseCode(code = 201, condition = "VIP created successfully"),
+        @ResponseCode(code = 404, condition = "The Container Name not found"),
+        @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+        @ResponseCode(code = 409, condition = "VIP already exist"),
+        @ResponseCode(code = 415, condition = "Invalid input data")})
+    public Response addVIP(@PathParam("containerName") String containerName,
+            @TypeHint(VIP.class) VIP inVIP){
+
+        VIP vipInput = inVIP;
+        String name = vipInput.getName();
+        String ip = vipInput.getIp();
+        String protocol = vipInput.getProtocol();
+        short protocolPort = vipInput.getPort();
+        String poolName = vipInput.getPoolName();
+        if(name.isEmpty() ||
+                ip.isEmpty()||
+                protocol.isEmpty()||
+                protocolPort < 0 ){
+            throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+        }
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if(!configManager.vipExists(name, ip, protocol, protocolPort, poolName)){
+
+            VIP vip = configManager.createVIP(name, ip, protocol, protocolPort, poolName);
+            if ( vip != null){
+                return Response.status(Response.Status.CREATED).build();
+            }
+        }else{
+            throw new ResourceConflictException(NBConst.RES_VIP_ALREADY_EXIST);
+        }
+        throw new InternalServerErrorException(NBConst.RES_VIP_CREATION_FAILED);
+    }
+
+    @Path("/{containerName}/update/vip")
+    @PUT
+    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes( {
+        @ResponseCode(code = 201, condition = "VIP updated successfully"),
+        @ResponseCode(code = 404, condition = "The containerName not found"),
+        @ResponseCode(code = 503, condition = "VIP not found"),
+        @ResponseCode(code = 404, condition = "Pool not found"),
+        @ResponseCode(code = 405, condition = "Pool already attached to the VIP"),
+        @ResponseCode(code = 415, condition = "Invalid input name")})
+    public Response updateVIP(@PathParam("containerName") String containerName,
+            @TypeHint(VIP.class) VIP inVIP) {
+
+        VIP vipInput = inVIP;
+        String name = vipInput.getName();
+        String poolName = vipInput.getPoolName();
+        if(name.isEmpty() ||
+                poolName.isEmpty()){
+            throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+        }
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer "
+                                                + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if(!configManager.poolExists(poolName))
+            throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
+
+        if(configManager.getVIPAttachedPool(name)!=null)
+            throw new MethodNotAllowedException(NBConst.RES_VIP_POOL_EXIST);
+
+        if(configManager.updateVIP(name, poolName)!= null)
+            return Response.status(Response.Status.ACCEPTED).build();
+
+        throw new InternalServerErrorException(NBConst.RES_VIP_UPDATE_FAILED);
+    }
+
+    @Path("/{containerName}/delete/vip/{vipName}")
+    @DELETE
+    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes( {
+        @ResponseCode(code = 200, condition = "VIP deleted successfully"),
+        @ResponseCode(code = 404, condition = "The containerName not found"),
+        @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+        @ResponseCode(code = 404, condition = "VIP not found"),
+        @ResponseCode(code = 500, condition = "Failed to delete VIP")})
+    public Response deleteVIP(
+            @PathParam(value = "containerName") String containerName,
+            @PathParam(value = "vipName") String vipName) {
+
+        if(vipName.isEmpty())
+            throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer"
+                                            + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if(!configManager.vipExists(vipName))
+            throw new ResourceNotFoundException(NBConst.RES_VIP_NOT_FOUND);
+
+        for(VIP vip : configManager.getAllVIPs()){
+            if(vip.getName().equals(vipName)){
+                configManager.deleteVIP(vipName);
+                return Response.ok().build();
+            }
+        }
+        throw new InternalServerErrorException(NBConst.RES_VIP_DELETION_FAILED);
+    }
+
+    @Path("/{containerName}/create/pool")
+    @POST
+    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes( {
+        @ResponseCode(code = 201, condition = "Pool created successfully"),
+        @ResponseCode(code = 404, condition = "The containerName not found"),
+        @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+        @ResponseCode(code = 409, condition = "Pool already exist"),
+        @ResponseCode(code = 415, condition = "Invalid input data")})
+    public Response addPool(@PathParam("containerName") String containerName,
+            @TypeHint(Pool.class) Pool inPool) {
+
+        Pool poolInput = inPool;
+        String name = poolInput.getName();
+        String lbMethod =poolInput.getLbMethod();
+        if(name.isEmpty() ||
+                lbMethod.isEmpty()){
+            throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+        }
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer "
+                                            + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if(!configManager.poolExists(name)){
+
+            Pool pool = configManager.createPool(name, lbMethod);
+            if ( pool != null){
+                return Response.status(Response.Status.CREATED).build();
+            }
+        }else{
+            throw new ResourceConflictException(NBConst.RES_POOL_ALREADY_EXIST);
+        }
+        throw new InternalServerErrorException(NBConst.RES_POOL_CREATION_FAILED);
+    }
+
+    @Path("/{containerName}/delete/pool/{poolName}")
+    @DELETE
+    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes( {
+        @ResponseCode(code = 200, condition = "Pool deleted successfully"),
+        @ResponseCode(code = 404, condition = "The containerName not found"),
+        @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+        @ResponseCode(code = 404, condition = "Pool not found"),
+        @ResponseCode(code = 500, condition = "Failed to delete Pool")})
+    public Response deletePool(
+            @PathParam(value = "containerName") String containerName,
+            @PathParam(value = "poolName") String poolName) {
+
+        if(poolName.isEmpty())
+            throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer"
+                                        + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if(!configManager.poolExists(poolName))
+            throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
+
+        for(Pool pool:configManager.getAllPools()){
+            if(pool.getName().equals(poolName)){
+                configManager.deletePool(poolName);
+                return Response.ok().build();
+            }
+        }
+        throw new InternalServerErrorException(NBConst.RES_POOL_DELETION_FAILED);
+    }
+
+    @Path("/{containerName}/create/poolmember")
+    @POST
+    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes( {
+        @ResponseCode(code = 201, condition = "Pool member created successfully"),
+        @ResponseCode(code = 404, condition = "The containerName not found"),
+        @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+        @ResponseCode(code = 404, condition = "Pool not found"),
+        @ResponseCode(code = 409, condition = "Pool member already exist"),
+        @ResponseCode(code = 415, condition = "Invalid input data")})
+    public Response addPoolMember(@PathParam("containerName") String containerName,
+            @TypeHint(PoolMember.class) PoolMember inPoolMember){
+
+        PoolMember pmInput = inPoolMember;
+        String name = pmInput.getName();
+        String memberIP = pmInput.getIp();
+        String poolName = pmInput.getPoolName();
+
+        if(name.isEmpty() ||
+                memberIP.isEmpty()||
+                poolName.isEmpty()){
+            throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+        }
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer "
+                                        + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if(!configManager.poolExists(poolName))
+            throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
+
+        if(!configManager.memberExists(name, memberIP, poolName)){
+
+            PoolMember poolMember = configManager.addPoolMember(name, memberIP, poolName);
+            if ( poolMember != null){
+                return Response.status(Response.Status.CREATED).build();
+            }
+        }else{
+            throw new ResourceConflictException(NBConst.RES_POOLMEMBER_ALREADY_EXIST);
+        }
+        throw new InternalServerErrorException(NBConst.RES_POOLMEMBER_CREATION_FAILED);
+    }
+
+    @Path("/{containerName}/delete/poolmember/{poolMemberName}/{poolName}")
+    @DELETE
+    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes( {
+        @ResponseCode(code = 200, condition = "Pool member deleted successfully"),
+        @ResponseCode(code = 404, condition = "The containerName not found"),
+        @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
+        @ResponseCode(code = 404, condition = "Pool member not found"),
+        @ResponseCode(code = 404, condition = "Pool not found")})
+    public Response deletePoolMember(
+            @PathParam(value = "containerName") String containerName,
+            @PathParam(value = "poolMemberName") String poolMemberName,
+            @PathParam(value = "poolName") String poolName) {
+
+        if(poolMemberName.isEmpty()||
+                poolName.isEmpty())
+            throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
+
+        IConfigManager configManager = getConfigManagerService(containerName);
+
+        if (configManager == null) {
+            throw new ServiceUnavailableException("Load Balancer"
+                                        + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if(!configManager.poolExists(poolName))
+            throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
+
+        if(configManager.memberExists(poolMemberName, poolName)){
+
+            configManager.removePoolMember(poolMemberName, poolName);
+
+            return Response.ok().build();
+        }
+        throw new ResourceNotFoundException(NBConst.RES_POOLMEMBER_NOT_FOUND);
+    }
+}