Merge "fixed method name"
authorGiovanni Meo <gmeo@cisco.com>
Thu, 11 Apr 2013 17:07:53 +0000 (17:07 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 11 Apr 2013 17:07:54 +0000 (17:07 +0000)
31 files changed:
opendaylight/distribution/opendaylight/pom.xml
opendaylight/samples/loadbalancer/pom.xml [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/ConfigManager.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/IConfigManager.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/LBConst.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/LBUtil.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/Client.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/Pool.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/PoolMember.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/VIP.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/Activator.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerService.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/ILoadBalancingPolicy.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/RandomLBPolicy.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/RoundRobinLBPolicy.java [new file with mode: 0644]
opendaylight/samples/loadbalancer/src/test/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerTest.java [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/enunciate.xml [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/pom.xml [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthbound.java [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthboundRSApplication.java [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/NBConst.java [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/Pools.java [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/VIPs.java [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.factories [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.handlers [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.schemas [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.tooling [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/spring/context.xml [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/spring/servlet/security.xml [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/web.xml [new file with mode: 0644]
opendaylight/web/root/src/main/resources/js/one.js

index f6f9a018300e15c4fb34f65aeeed575fdfd5bebd..f6a7808b23f314593539de8b1e6ae278fcc96893 100644 (file)
@@ -86,6 +86,8 @@
        
     <!-- Samples -->
     <module>../../samples/simpleforwarding</module>
+    <module>../../samples/loadbalancer</module>
+    <module>../../samples/northbound/loadbalancer</module>
   </modules>
   
   <build>
diff --git a/opendaylight/samples/loadbalancer/pom.xml b/opendaylight/samples/loadbalancer/pom.xml
new file mode 100644 (file)
index 0000000..aaf1a18
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+       xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.opendaylight.controller</groupId>
+               <artifactId>commons.opendaylight</artifactId>
+               <version>1.4.0-SNAPSHOT</version>
+               <relativePath>../../commons/opendaylight</relativePath>
+       </parent>
+       <groupId>org.opendaylight.controller</groupId>
+       <artifactId>samples.loadbalancer</artifactId>
+       <version>0.4.0-SNAPSHOT</version>
+       <packaging>bundle</packaging>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <version>2.3.6</version>
+                               <extensions>true</extensions>
+                               <configuration>
+                                       <instructions>
+                                               <Export-Package>
+                                                       org.opendaylight.controller.samples.loadbalancer,
+                                                       org.opendaylight.controller.samples.loadbalancer.entities,
+                                                       org.opendaylight.controller.samples.loadbalancer.internal,
+                                                       org.opendaylight.controller.samples.loadbalancer.policies
+                                               </Export-Package>
+                                               <Import-Package>
+                                                       org.opendaylight.controller.sal.core,
+                                                       org.opendaylight.controller.sal.utils,
+                                                       org.opendaylight.controller.sal.action,
+                                                       org.opendaylight.controller.sal.match,
+                                                       org.opendaylight.controller.sal.packet,
+                                                       org.opendaylight.controller.sal.routing,
+                                                       org.opendaylight.controller.sal.flowprogrammer,
+                                                       org.opendaylight.controller.sal.packet.address,
+                                                       org.opendaylight.controller.hosttracker,
+                                                       org.opendaylight.controller.hosttracker.hostAware,
+                                                       org.opendaylight.controller.samples.loadbalancer,
+                                                       org.opendaylight.controller.samples.loadbalancer.entities,
+                                                       org.opendaylight.controller.samples.loadbalancer.internal,
+                                                       org.opendaylight.controller.samples.loadbalancer.policies,
+                                                       org.opendaylight.controller.topologymanager,
+                                                       org.opendaylight.controller.forwardingrulesmanager,
+                                                       org.opendaylight.controller.switchmanager,
+                                                       org.opendaylight.controller.clustering.services,
+                                                       javax.xml.bind.annotation,
+                                                       javax.xml.bind,
+                                                       org.apache.felix.dm,
+                                                       org.apache.commons.lang3.builder,
+                                                       org.osgi.service.component,
+                                                       org.slf4j,
+                                                       org.eclipse.osgi.framework.console,
+                                                       org.osgi.framework
+                                               </Import-Package>
+                                               <Bundle-Activator>
+                                                       org.opendaylight.controller.samples.loadbalancer.internal.Activator
+                                               </Bundle-Activator>
+                                               <Service-Component>
+                                               </Service-Component>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+       <dependencies>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>topologymanager</artifactId>
+                       <version>0.4.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>switchmanager</artifactId>
+                       <version>0.4.0-SNAPSHOT</version>
+               </dependency>
+           <dependency>
+               <groupId>org.opendaylight.controller</groupId>
+               <artifactId>forwardingrulesmanager</artifactId>
+               <version>0.4.0-SNAPSHOT</version>
+       </dependency>
+       <dependency>
+               <groupId>org.opendaylight.controller</groupId>
+               <artifactId>hosttracker</artifactId>
+               <version>0.4.0-SNAPSHOT</version>
+       </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal</artifactId>
+                       <version>0.4.0-SNAPSHOT</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/ConfigManager.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/ConfigManager.java
new file mode 100644 (file)
index 0000000..3cacab7
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents a configuration manager for the Load Balancer service.
+ * This class is responsible for managing(store/update/delete) the load balancer 
+ * configuration that it receives through REST APIs or from any other applications
+ * present in the controller.
+ *
+ */
+public class ConfigManager implements IConfigManager{
+    
+    /*
+     * Logger instance
+     */
+    private static final Logger cmLogger = LoggerFactory.getLogger(ConfigManager.class);
+    
+    /*
+     * All the available VIPs 
+     */
+    private HashMap<String,VIP> vips = new HashMap<String,VIP>();
+    
+    /*
+     * All the available Pools
+     */
+    private HashMap<String,Pool> pools = new HashMap<String,Pool>();
+    
+    public ConfigManager(){
+    }
+    
+    @Override
+    public boolean vipExists(String name) {
+        return this.vips.containsKey(name);
+    }
+    
+    @Override
+    public boolean vipExists(VIP vip){
+        if(vip.getName()==null){
+            if(!vips.containsValue(vip)){
+                return false;
+            }
+        }else{
+            if(!vips.containsKey(vip.getName())){
+                if(!vips.containsValue(vip)){
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+    
+    @Override
+    public boolean vipExists(String name,String ip,String protocol,short protocolPort,String poolName){
+        
+        VIP vip = new VIP(name,ip,protocol,protocolPort,poolName);
+        
+        //Check VIP with the same name
+        
+        if(!vips.containsKey(name)){
+            //Check VIP with the same ip, protocol and protocolPort
+            if(!vips.containsValue(vip)){
+                
+                //if you reach here, means this VIP don't exist
+                return false;
+            }
+        }
+        
+        //Yeah, i have it.
+       return true;
+    }
+    
+    @Override
+    public Set<VIP> getAllVIPs(){
+        return new HashSet<VIP>(this.vips.values());
+    }
+    
+    public VIP getVIPWithPoolName(VIP vip){
+        cmLogger.info("Search a VIP with name:{}",vip);
+        for(VIP vipTemp: this.vips.values()){
+            if(vipTemp.equals(vip)){
+                
+                cmLogger.info("Found VIP with pool detail : {}",vipTemp);
+                return vipTemp;
+            }
+        }
+        
+        cmLogger.info("VIP with pool detail not found ");
+        return null;
+    }
+    
+    @Override
+    public VIP createVIP(String name,String ip,String protocol,short protocolPort,String poolName){
+        
+        cmLogger.info("Create VIP with the following details :[ name : "+name
+                                                                    +" ip : "+ip
+                                                                    +" protocol : "+protocol
+                                                                    +" protocol_port : "+protocolPort
+                                                                    +" pool name : "+poolName);
+        
+        VIP vip = new VIP(name,ip,protocol,protocolPort,poolName);
+        
+        if(poolName !=null && !poolName.isEmpty()){
+            if(pools.containsKey(poolName)){
+                pools.get(poolName).addVIP(vip);
+            }
+        }
+        
+        vip.setStatus(LBConst.STATUS_ACTIVE);
+        this.vips.put(name, vip);
+        
+        cmLogger.info("New VIP created : "+vip.toString());
+        return vip;
+    }
+    
+    @Override
+    public String getVIPAttachedPool(String name) {
+        return this.vips.get(name).getPoolName();
+    }
+    
+    @Override
+    public VIP updateVIP(String name, String poolName){
+        
+        cmLogger.info("Updating VIP : "+name+" pool name  to "+poolName);
+        
+        if(vips.containsKey(name)){
+            VIP vip = vips.get(name);
+            if(vip.getPoolName() == null){
+                vip.setPoolName(poolName);
+                cmLogger.error("VIP is now attached to the pool : {}",vip.toString());
+                return vip;
+            }
+            cmLogger.error("VIP is already attached to one pool : {}",vip.toString());
+        }
+        cmLogger.error("VIP with name: "+name+" does not exist");
+        return null;
+    }
+    
+    @Override
+    public VIP deleteVIP(String name){
+        
+        cmLogger.info("Deleting VIP : "+name);
+        
+        VIP vip = vips.get(name);
+        
+        String poolName = vip.getPoolName();
+        
+        if(poolName != null){
+            if(pools.containsKey(poolName)){
+                Pool pool = pools.get(poolName);
+                pool.removeVIP(vip.getName());
+            }
+        }
+        
+        cmLogger.info("VIP removed : "+vip.toString());
+        
+        vips.remove(vip.getName());
+        
+        return vip;
+    }
+    
+    @Override
+    public boolean memberExists(String name, String poolName) {
+        if(this.pools.containsKey(poolName)){
+            if(this.pools.get(poolName).getMember(name) != null )
+                return true;
+        }
+        return false;
+    }
+    
+    @Override
+    public boolean memberExists(String name, String memberIP,String poolName){
+        if(!this.pools.containsKey(poolName))
+            return false;
+        
+        return this.pools.get(poolName).poolMemberExists(new PoolMember(name, memberIP, poolName));
+    }
+    
+    @Override
+    public PoolMember addPoolMember(String name, String memberIP, String poolName){
+        
+        PoolMember pm = new PoolMember(name,memberIP,poolName);
+        
+        cmLogger.info("Adding pool member : "+pm.toString());
+        
+        pools.get(poolName).addMember(pm);
+        
+        return pm;
+    }
+    
+    @Override
+    public PoolMember removePoolMember(String name, String poolName){
+        
+        cmLogger.info("Removing pool member : {} from pool {}",name, poolName);
+        
+        Pool pool = pools.get(poolName);
+        
+        PoolMember pm = pool.getMember(name);
+        
+        pool.removeMember(name);
+        
+        cmLogger.info("Pool member {} removed from {} ",name,poolName);
+        
+        return pm;
+    }
+    
+    @Override
+    public Set<Pool> getAllPools(){
+        return new HashSet<Pool>(this.pools.values());
+    }
+    
+    @Override
+    public boolean poolExists(String name) {
+        return this.pools.containsKey(name);
+    }
+    
+    @Override
+    public boolean poolExists(String name, String lbMethod){
+        
+        return pools.containsValue(new Pool(name,lbMethod));
+    }
+    
+    @Override
+    public Pool createPool(String name, String lbMethod){
+        
+        Pool newPool = new Pool(name,lbMethod);
+        
+        cmLogger.info("New pool created : " + newPool.toString());
+        
+        pools.put(name, newPool);
+        
+        return newPool;
+    }
+    
+    @Override
+    public Pool deletePool(String poolName){
+        
+        Pool pool = pools.get(poolName);
+        
+        for(VIP vip:pool.getAllVip()){
+            
+            vip.setPoolName(null);
+            
+        }
+        
+        cmLogger.info("Pool removed : "+pool.toString());
+        
+        pools.remove(poolName);
+        
+        return pool;
+    }
+    
+    @Override
+    public Pool getPool( String poolName){
+        if(pools.containsKey(poolName)){
+            return pools.get(poolName);
+        }
+        return null;
+    }
+    
+    @Override
+    public Set<PoolMember> getAllPoolMembers(String poolName) {
+        
+        if(pools.containsKey(poolName)){
+            return new HashSet<PoolMember>(pools.get(poolName).getAllMembers());
+        }
+        return null;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "ConfigManager [vips=" + vips + ", pools=" + pools + "]";
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/IConfigManager.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/IConfigManager.java
new file mode 100644 (file)
index 0000000..df35b0a
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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;
+
+import java.util.Set;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+
+/**
+ * Interface implemented by the configuration manager.
+ *
+ */
+public interface IConfigManager {
+    
+    /**
+     * Return all existing VIPs
+     * @return Set of VIP's
+     * if there is no VIP, it will return empty set.
+     */
+    public Set<VIP> getAllVIPs();
+    
+    /**
+     * Check if VIP with the 'name' exists
+     * @param name     Name of the VIP 
+     * @return true    if exists
+     *                         false   else
+     */
+    public boolean vipExists(String name);
+
+    /**
+     * Check if VIP exists with the details 'VIP' 
+     * @param vip Search for this VIP 
+     * @return true    if exists
+     *                         false   else
+     */
+    public boolean vipExists(VIP vip);
+
+    /**
+     * Check if VIP with the provided details exists
+     * @param name     Name of the VIP
+     * @param ip       IP of the VIP
+     * @param protocol IP Protocol of the VIP (TCP/UDP)
+     * @param protocolPort     Transport port of the VIP (e.g 5550)
+     * @param poolName Name of the pool attached with the VIP
+     * @return true    if exists
+     *                         false   else
+     */
+    public boolean vipExists(String name,String ip,String protocol,short protocolPort,String poolName);
+    
+    /**
+     * Add VIP to the configuration
+     * @param name     Name of the VIP
+     * @param ip       IP of the VIP
+     * @param protocol IP Protocol of the VIP (TCP/UDP)
+     * @param protocolPort     Transport port of the VIP
+     * @param poolName Name of the pool that VIP will use for load balancing its traffic
+     * @return Newly created VIP
+     */
+    public VIP createVIP(String name,String ip,String protocol,short protocolPort,String poolName);
+    
+    /**
+     * Return pool attached to VIP
+     * @param name Name of the VIP
+     * @return Name of the pool attached to VIP
+     *                         else null
+     */
+    public String getVIPAttachedPool(String name);
+    /**
+     * Update pool name of the VIP.
+     * @param name     Name of the VIP
+     * @param poolName Attach this pool to VIP
+     * @return Updated VIP     If successful
+     *                         null                    If this VIP is already attached to any existing pool.
+     */                        
+    public VIP updateVIP(String name, String poolName);
+    
+    /**
+     * Delete the VIP
+     * @param name     Delete VIP with this name
+     * @return Details of the deleted VIP
+     */
+    public VIP deleteVIP(String name);
+
+    /**
+     * Check if pool member with the 'name' present in the pool with name 'poolName' 
+     * @param name     Name of the pool member 
+     * @param poolName Name of the pool, you want to search for pool member
+     * @return true    If exist
+     *                         false   else
+     */
+    public boolean memberExists(String name, String poolName);
+
+    /**
+     * Check if pool member with name 'name' and IP 'memberIP' exist in the pool 'poolName'
+     * @param name     Name of the pool member
+     * @param memberIP IP of the pool member
+     * @param poolName Name of the pool member you want to search
+     * @return true    If Exist
+     *                         false   else
+     */
+    public boolean memberExists(String name, String memberIP,String poolName);
+    
+    /**
+     * Return all  pool members of the pool 'poolName'
+     * @param poolName Name of the pool
+     * @return Set of all the pool members             if pool with the name present in the configuration
+     *                         null                                                    else
+     *                         
+     */
+    public Set<PoolMember> getAllPoolMembers(String poolName);
+    
+    /**
+     * Add new pool member to the configuration
+     * @param name     Name of the pool
+     * @param memberIP IP of the pool
+     * @param poolName Attach pool member to this pool
+     * @return Newly created pool member 
+     */
+    public PoolMember addPoolMember(String name, String memberIP, String poolName);
+    
+    /**
+     * Remove pool member from the pool
+     * @param name     Name of the pool member
+     * @param poolName Name of the pool
+     * @return Details of the removed pool member 
+     */
+    public PoolMember removePoolMember(String name, String poolName);
+
+    /**
+     * Return all the existing pools
+     * @return Set of Pools
+     */
+    public Set<Pool> getAllPools();
+    
+    /**
+     * Return pool with input name
+     * @param poolName Name of the pool
+     * @return Details of the pool     if pool exist
+     *                         null                                    else
+     */
+    public Pool getPool(String poolName);
+    
+    /**
+     * Check if pool exists with the input name 
+     * @param name     Name of the pool
+     * @return true    If exists
+     *                         false   else
+     */
+    public boolean poolExists(String name);
+
+    /**
+     * Check if pool exists with the input name and loadbalancing method.
+     * @param name     Name of the pool 
+     * @param lbMethod Load balancing method name
+     * @return true    If exists
+     *                         false   else
+     */
+    public boolean poolExists(String name, String lbMethod);
+    
+    /**
+     * Create new pool with the provided details
+     * @param name     Name of the pool
+     * @param lbMethod Load balancing method this pool will use
+     * @return Details of the newly created pool
+     */
+    public Pool createPool(String name, String lbMethod);
+    
+    /**
+     * Delete pool with the provided name
+     * @param poolName Name of the pool
+     * @return Details of the deleted pool
+     */
+    public Pool deletePool(String poolName);
+
+}
\ No newline at end of file
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/LBConst.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/LBConst.java
new file mode 100644 (file)
index 0000000..7e93304
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * Class defines all the constants used by load balancer service
+ *
+ */
+public class LBConst {
+    
+    public static final int FORWARD_DIRECTION_LB_FLOW = 0;
+    
+    public static final int REVERSE_DIRECTION_LB_FLOW = 1;
+    
+    public static final String ROUND_ROBIN_LB_METHOD = "roundrobin";
+    
+    public static final String RANDOM_LB_METHOD = "random";
+    
+    public static final String STATUS_ACTIVE="active";
+    
+    public static final String STATUS_INACTIVE="inactive";
+    
+    public static final String STATUS_PENDING="pending";
+    
+    public static final String STATUS_ERROR="error";
+       
+}
+
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/LBUtil.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/LBUtil.java
new file mode 100644 (file)
index 0000000..c320250
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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;
+
+import org.opendaylight.controller.sal.packet.IPv4;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.TCP;
+import org.opendaylight.controller.sal.packet.UDP;
+import org.opendaylight.controller.sal.utils.IPProtocols;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class defines utilty methods that will be used by different components 
+ * of the load balancer service 
+ *
+ */
+public class LBUtil {
+    
+    private static final Logger lbuLogger = LoggerFactory.getLogger(LBUtil.class);
+    
+    public LBUtil(){}
+    
+    /**
+     * Extract the details of the source machine that sent this packet 'inPkt'  
+     * @param inPkt    Packet that is received by the controller
+     * @return Details of the source machine in Client object.
+     */
+    public Client getClientFromPacket(IPv4 inPkt){
+        lbuLogger.info("Find client information from packet : {}",inPkt.toString());
+        
+        String ip = NetUtils.getInetAddress(inPkt.getSourceAddress()).getHostAddress();
+        
+        String protocol = IPProtocols.getProtocolName(inPkt.getProtocol());
+        
+        lbuLogger.info("client ip {} and protocl {}",ip,protocol);
+        
+        Packet tpFrame= inPkt.getPayload();
+        
+        lbuLogger.info("Get protocol layer {}",tpFrame.toString());
+        
+        short port = 0;
+        
+        if(protocol.equals(IPProtocols.TCP.toString())){
+            TCP tcpFrame = (TCP)tpFrame;
+            port = tcpFrame.getSourcePort();
+        }else{
+            UDP udpFrame = (UDP)tpFrame;
+            port = udpFrame.getSourcePort();
+        }
+        
+        lbuLogger.info("Found port {}",port);
+        
+        Client source = new Client(ip, protocol,port);
+        
+        lbuLogger.info("Client information : {}",source.toString());
+        
+        return source;
+    }
+    
+    /**
+     * Extract the details of the destination machine where this packet 'inPkt' need
+     * to be delivered
+     * @param inPkt Packet that is received by controller for forwarding
+     * @return Details of the destination machine packet in VIP
+     */
+    public VIP getVIPFromPacket(IPv4 inPkt){
+        
+        lbuLogger.info("Find VIP information from packet : {}",inPkt.toString());
+        
+        String ip = NetUtils.getInetAddress(inPkt.getDestinationAddress()).getHostAddress();
+        
+        String protocol = IPProtocols.getProtocolName(inPkt.getProtocol());
+        
+        Packet tpFrame= inPkt.getPayload();
+        
+        short port = 0;
+        
+        if(protocol.equals(IPProtocols.TCP.toString())){
+            TCP tcpFrame = (TCP)tpFrame;
+            port = tcpFrame.getDestinationPort();
+        }else{
+            
+            UDP udpFrame = (UDP)tpFrame;
+            port = udpFrame.getDestinationPort();
+        }
+        
+        VIP dest = new VIP(null,ip, protocol,port,null);
+        
+        lbuLogger.info("VIP information : {}",dest.toString());
+        
+        return dest;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/Client.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/Client.java
new file mode 100644 (file)
index 0000000..4d7cf49
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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.entities;
+
+/**
+ * This class represents the source host that sends any traffic to any existing virtual IP (VIP).
+ * This source host is referred to as a 'Client'. Clients will be differentiated from each other
+ * based on the following three properties:
+ * 1. IP address of the client.
+ * 2. Protocol of the traffic it is using for sending traffic
+ * 3. Source port from which it is sending traffic.
+ * e.g TCP traffic from two different ports from the same host to a given VIP will be considered
+ * as two different clients by this service. Similarly, traffic using two different protocols
+ * (TCP, UDP) from the same host will be considered as two different clients.
+ * 
+ */
+public class Client {
+    
+    /*
+     * IP address of the client (source address)
+     */
+    private String ip;
+    
+    /*
+     * Network protocol of the traffic sent by client
+     */
+    private String protocol;
+    
+    /*
+     * Port used to send network traffic (source port)
+     */
+    private short port;
+    
+    public Client(String ip, String protocol, short port){
+        this.ip = ip;
+        this.protocol = protocol;
+        this.port = port;
+    }
+    
+    /**
+     * @return the client IP
+     */
+    public String getIp() {
+        return ip;
+    }
+    
+    /**
+     * @param ip the IP to set
+     */
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+    
+    /**
+     * @return the client network protocol
+     */
+    public String getProtocol() {
+        return protocol;
+    }
+    
+    /**
+     * @param protocol the protocol to set
+     */
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+    
+    /**
+     * @return the client port
+     */
+    public short getPort() {
+        return port;
+    }
+    
+    /**
+     * @param port the port to set
+     */
+    public void setPort(short port) {
+        this.port = port;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+        result = prime * result + port;
+        result = prime * result+ ((protocol == null) ? 0 : protocol.hashCode());
+        return result;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof Client)) {
+            return false;
+        }
+        Client other = (Client) obj;
+        if (ip == null) {
+            if (other.ip != null) {
+                return false;
+            }
+        }else if (!ip.equals(other.ip)) {
+            return false;
+        }
+        if (port != other.port) {
+            return false;
+        }
+        if (protocol == null) {
+            if (other.protocol != null) {
+                return false;
+            }
+        }else if (!protocol.equals(other.protocol)) {
+            return false;
+        }
+        return true;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "Client [ip=" + ip + ", protocol=" + protocol + ", port=" + port+ "]";
+    }
+}
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/Pool.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/Pool.java
new file mode 100644 (file)
index 0000000..bbf3116
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * 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.entities;
+
+import java.util.ArrayList;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * This class represents the pool of hosts among which incoming traffic
+ * will be load balanced. Each pool will load balance the traffic among its pool members 
+ * based on the loadbalancing policy set for the pool. 
+ * Currently, the pool supports two load balancing policies:
+ * 1. Round Robin Policy{@link org.opendaylight.controller.samples.loadbalancer.policies.RoundRobinLBPolicy}
+ * 2. Random Policy {@link org.opendaylight.controller.samples.loadbalancer.policies.RandomLBPolicy}
+ * 
+ * NOTE: After creation of the pool, user can't update (change) its load balancing policy.
+ * NOTE: Each Pool should have a unique name.
+ */
+
+@XmlRootElement(name="pool")
+@XmlAccessorType(XmlAccessType.NONE)
+public class Pool {
+    
+    /*
+     * Unique name of the pool
+     */
+    @XmlElement
+    private String name;
+    
+    /*
+     * Associated load balancing policy
+     */
+    @XmlElement(name="lbmethod")
+    private String lbMethod;
+    
+    /*
+     * Status of the pool (active/inactive)
+     */
+    @XmlElement
+    private String status;
+    
+    /*
+     * List of all the VIPs using this pool for load balancing their traffic - more than
+     * one VIP can be mapped to each pool.
+     */
+    @XmlElement
+    private ArrayList<VIP> vips = new ArrayList<VIP>();
+    
+    /*
+     * List of all the pool members used for load balancing the traffic
+     */
+    @XmlElement
+    private ArrayList<PoolMember> members = new ArrayList<PoolMember>();
+    
+    /*
+     * Private constructor used for JAXB mapping
+     */
+    @SuppressWarnings("unused")
+    private Pool() {}
+    
+    /**
+     * Getter/ Setter methods
+     */
+    
+    public Pool(String name,
+                    String lbMethod) {
+        this.name = name;
+        this.lbMethod = lbMethod;
+    }
+    
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+    
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    /**
+     * @return the lbMethod
+     */
+    public String getLbMethod() {
+        return lbMethod;
+    }
+    
+    /**
+     * @param lbMethod the lbMethod to set
+     */
+    public void setLbMethod(String lbMethod) {
+        this.lbMethod = lbMethod;
+    }
+    
+    /**
+     * @return the status
+     */
+    public String getStatus() {
+        return status;
+    }
+    
+    /**
+     * @param status the status to set
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+    
+    /**
+     * @return the vip
+     */
+    public ArrayList<VIP> getAllVip() {
+        return vips;
+    }
+    
+    /**
+     * @param vip the vip to set
+     */
+    public void setVips(ArrayList<VIP> vips) {
+        this.vips = vips;
+    }
+    
+    /**
+     * @return the members
+     */
+    public ArrayList<PoolMember> getAllMembers() {
+        return members;
+    }
+    
+    /**
+     * @param members the members to set
+     */
+    public void setMembers(ArrayList<PoolMember> members) {
+        this.members = members;
+    }
+    
+    /**
+     * Add new VIP to the VIP list
+     * @param vip       new VIP to add
+     */
+    public void addVIP(VIP vip){
+        this.vips.add(vip);
+    }
+    
+    /**
+     * Remove VIP with given name from the VIP list of the pool
+     * @param name      Name of the VIP
+     * @return true     If VIP was using this pool and removed
+     *          false   IF VIP is not using this pool
+     */
+    public boolean removeVIP(String name){
+        for(VIP vip: this.vips){
+            if(vip.getName().equals(name)){
+                this.members.remove(vip);
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Check if the given pool member is part of this pool
+     * @param pm        Search for this pool member
+     * @return true     If pool member is attached to this pool
+     *          false   else
+     */
+    public boolean poolMemberExists(PoolMember pm){
+        return this.members.contains(pm);
+    }
+    
+    /**
+     * Returns the pool member with the given name
+     * @param name      Search for this pool member
+     * @return PoolMember       If pool member is attached to this pool
+     *          null            else
+     */
+    public PoolMember getMember(String name){
+        
+        for(PoolMember pm: this.members){
+            if(pm.getName().equals(name)){
+                return pm;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Add new pool member to the pool
+     * @param pm        Add this new pool
+     */
+    public void addMember(PoolMember pm){
+        this.members.add(pm);
+    }
+    
+    /**
+     * Remove pool member from the pool list
+     * @param name Remove this pool member
+     * @return true    If pool member was attached to this pool and successfully removed
+     *          false  If pool member is not attached to this pool
+     */
+    public boolean removeMember(String name){
+        for(PoolMember pm: this.members){
+            if(pm.getName().equals(name)){
+                this.members.remove(pm);
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result+ ((lbMethod == null) ? 0 : lbMethod.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        return result;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof Pool)) {
+            return false;
+        }
+        Pool other = (Pool) obj;
+        if (lbMethod == null) {
+            if (other.lbMethod != null) {
+                return false;
+            }
+        }else if (!lbMethod.equals(other.lbMethod)) {
+            return false;
+        }
+        if (name == null) {
+            if (other.name != null) {
+                return false;
+            }
+        }else if (!name.equals(other.name)) {
+            return false;
+        }
+        return true;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "Pool [name=" + name + ", lbMethod=" + lbMethod + ", status="
+                            + status + ", vips=" + vips + ", members=" + members + "]";
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/PoolMember.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/PoolMember.java
new file mode 100644 (file)
index 0000000..31297eb
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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.entities;
+
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * This class represents the host where load balancing service will
+ * redirect VIP traffic for load balancing. All these hosts have to
+ * register with a pool to be a part of traffic load balancing.
+ * This entity is referred to as a 'PoolMember'. 
+ * Load balancer service differentiates each pool member based on its 
+ * two properties { ip address, attached pool }.
+ * A host (IP) can be attached to two different pools through creation of two
+ * different pool member objects.
+ * 
+ * NOTE: Each pool member should have a unique name.
+ *
+ */
+@XmlRootElement(name="poolmember")
+@XmlAccessorType(XmlAccessType.NONE)
+public class PoolMember {
+    
+    /*
+     * Unique name of the pool member
+     */
+    @XmlElement
+    private String name;
+    
+    /*
+     * IP address of the pool member
+     */
+    @XmlElement
+    private String ip;
+    
+    /*
+     * Name of the pool this member is attached to.
+     */
+    @XmlElement(name="poolname")
+    private String poolName;
+    
+    /*
+     * Status (active/inactive)
+     */
+    @XmlElement
+    private String status;
+    
+    /**
+     * Private constructor used for JAXB mapping
+     */
+    @SuppressWarnings("unused")
+    private PoolMember() {}
+    
+    public PoolMember(String name, String memberIP, String poolName){
+        this.name = name;
+        this.ip = memberIP;
+        this.poolName = poolName;
+    }
+    
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+    
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    /**
+     * @return the ip
+     */
+    public String getIp() {
+        return ip;
+    }
+    
+    /**
+     * @param ip the ip to set
+     */
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+    
+    /**
+     * @return the poolName
+     */
+    public String getPoolName() {
+        return poolName;
+    }
+    
+    /**
+     * @param poolName the poolName to set
+     */
+    public void setPoolName(String poolName) {
+        this.poolName = poolName;
+    }
+    
+    /**
+     * @return the status
+     */
+    public String getStatus() {
+        return status;
+    }
+    
+    /**
+     * @param status the status to set
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+        result = prime * result
+                + ((poolName == null) ? 0 : poolName.hashCode());
+        return result;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof PoolMember)) {
+            return false;
+        }
+        PoolMember other = (PoolMember) obj;
+        if (ip == null) {
+            if (other.ip != null) {
+                return false;
+            }
+        }else if (!ip.equals(other.ip)) {
+            return false;
+        }
+        if (poolName == null) {
+            if (other.poolName != null) {
+                return false;
+            }
+        }else if (!poolName.equals(other.poolName)) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "PoolMember [name=" + name + ", ip=" + ip + ", poolName="
+                                    + poolName + ", status=" + status + "]";
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/VIP.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/VIP.java
new file mode 100644 (file)
index 0000000..6f866fe
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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.entities;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * This class represents the Virtual IP  (VIP) address exposed by the load balancer application.
+ * Load balancer service differentiates one VIP from the other, using the following three properties:
+ * 1. IP address of the VIP exposed by the application
+ * 2. Protocol of the network traffic (TCP/UDP)
+ * 3. Port to which incoming traffic is destined
+ * 
+ * User is allowed to create mutliple VIPs with the same IP, but all such VIPs (with the same IP) 
+ * should differ at least in the protocol or port or both.
+ * 
+ * NOTE: Each VIP should have a unique name.
+ */
+@XmlRootElement(name="vip")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class VIP {
+    
+    /*
+     * Unique name of the VIP
+     */
+    @XmlElement
+    private String name;
+    
+    /*
+     * Virtual IP address of the VIP 
+     */
+    @XmlElement
+    private String ip;
+    
+    /*
+     * Network traffic protocol 
+     */
+    @XmlElement
+    private String protocol;
+    
+    /*
+     * Port where network traffic is destined (destination port)
+     */
+    @XmlElement
+    private short port;
+    
+    /*
+     * Name of the pool attached to the VIP for load balancing its traffic
+     */
+    @XmlElement(name="poolname")
+    private String poolName;
+    
+    /*
+     * Status (Active/inactive)
+     */
+    @XmlElement
+    private String status;
+
+    /**
+     * Private constructor used for JAXB mapping
+     */
+    @SuppressWarnings("unused")
+    private VIP() {}
+    
+    public VIP(String name,
+                String ip,
+                String protocol,
+                short port,
+                String poolName){
+        this.name = name;
+        this.ip=ip;
+        this.protocol=protocol;
+        this.port = port;
+        this.poolName = poolName;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    public String getIp() {
+        return ip;
+    }
+    
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+    
+    public String getProtocol() {
+        return protocol;
+    }
+    
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+    
+    public short getPort() {
+        return port;
+    }
+    
+    public void setPort(short port) {
+        this.port = port;
+    }
+    
+    public String getPoolName() {
+        return poolName;
+    }
+    
+    public void setPoolName(String poolName) {
+        this.poolName = poolName;
+    }
+    
+    /**
+     * @return the status
+     */
+    public String getStatus() {
+        return status;
+    }
+    
+    /**
+     * @param status the status to set
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+        result = prime * result + port;
+        result = prime * result
+                + ((protocol == null) ? 0 : protocol.hashCode());
+        return result;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+            
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof VIP)) {
+            return false;
+        }
+        
+        VIP other = (VIP) obj;
+        if (ip == null) {
+            if (other.ip != null) {
+                return false;
+            }
+        }else if (!ip.equals(other.ip)) {
+            return false;
+        }
+        if (port != other.port) {
+            return false;
+        }
+        if (protocol == null) {
+            if (other.protocol != null) {
+                return false;
+            }
+        }else if (!protocol.equalsIgnoreCase(other.protocol)) {
+            return false;
+        }
+        return true;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "VIP [name=" + name + ", ip=" + ip + ", protocol=" + protocol
+                            + ", port=" + port + ", poolName=" + poolName + ", status="
+                            + status + "]";
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/Activator.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/Activator.java
new file mode 100644 (file)
index 0000000..0568fce
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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.internal;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.dm.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
+import org.opendaylight.controller.samples.loadbalancer.IConfigManager;
+
+/**
+ * Main application activator class for registering the dependencies and 
+ * initialising the load balancer application.
+ *
+ */
+
+public class Activator extends ComponentActivatorAbstractBase {
+    
+    /*
+     * Logger instance
+     */
+    protected static final Logger logger = LoggerFactory.getLogger(Activator.class);
+
+    /**
+     * Function called when the activator starts just after some
+     * initializations are done by the
+     * ComponentActivatorAbstractBase.
+     *
+     */
+    public void init() {
+    }
+
+    /**
+     * Function called when the activator stops just before the
+     * cleanup done by ComponentActivatorAbstractBase
+     *
+     */
+    public void destroy() {
+    }
+
+    /**
+     * Function that is used to communicate to dependency manager the
+     * list of known implementations for services inside a container
+     *
+     *
+     * @return An array containing all the CLASS objects that will be
+     * instantiated in order to get an fully working implementation
+     * Object
+     */
+    public Object[] getImplementations() {
+        Object[] res = { LoadBalancerService.class };
+        return res;
+    }
+
+    /**
+     * Function that is called when configuration of the dependencies
+     * is required.
+     *
+     * @param c dependency manager Component object, used for
+     * configuring the dependencies exported and imported
+     * @param imp Implementation class that is being configured,
+     * needed as long as the same routine can configure multiple
+     * implementations
+     * @param containerName The containerName being configured, this allow
+     * also optional per-container different behavior if needed, usually
+     * should not be the case though.
+     */
+    public void configureInstance(Component c, Object imp, String containerName) {
+        if (imp.equals(LoadBalancerService.class)) {
+            // export the service
+            Dictionary<String, String> props = new Hashtable<String, String>();
+            props.put("salListenerName", "loadbalancer");
+
+            c.setInterface(new String[] { IListenDataPacket.class.getName(),
+                       IConfigManager.class.getName()}, props);
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IDataPacketService.class).setCallbacks(
+                    "setDataPacketService", "unsetDataPacketService")
+                    .setRequired(true));
+            
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IRouting.class).setCallbacks("setRouting", "unsetRouting")
+                    .setRequired(false));
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IfIptoHost.class).setCallbacks("setHostTracker",
+                    "unsetHostTracker").setRequired(true));
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IForwardingRulesManager.class).setCallbacks(
+                    "setForwardingRulesManager", "unsetForwardingRulesManager")
+                    .setRequired(true));
+        }
+    }
+
+    /**
+     * Method which tells how many Global implementations are
+     * supported by the bundle. This way we can tune the number of
+     * components created. This components will be created ONLY at the
+     * time of bundle startup and will be destroyed only at time of
+     * bundle destruction, this is the major difference with the
+     * implementation retrieved via getImplementations where all of
+     * them are assumed to be in a container !
+     *
+     *
+     * @return The list of implementations the bundle will support,
+     * in Global version
+     */
+    protected Object[] getGlobalImplementations() {
+        return null;
+    }
+
+    /**
+     * Configure the dependency for a given instance Global
+     *
+     * @param c Component assigned for this instance, this will be
+     * what will be used for configuration
+     * @param imp implementation to be configured
+     * @param containerName container on which the configuration happens
+     */
+    protected void configureGlobalInstance(Component c, Object imp) {
+    }
+}
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerService.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerService.java
new file mode 100644 (file)
index 0000000..1c69be8
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * 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.internal;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.Output;
+import org.opendaylight.controller.sal.action.SetDlDst;
+import org.opendaylight.controller.sal.action.SetDlSrc;
+import org.opendaylight.controller.sal.action.SetNwDst;
+import org.opendaylight.controller.sal.action.SetNwSrc;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Path;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.packet.Ethernet;
+import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.packet.IPv4;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.PacketResult;
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.IPProtocols;
+import org.opendaylight.controller.samples.loadbalancer.ConfigManager;
+import org.opendaylight.controller.samples.loadbalancer.IConfigManager;
+import org.opendaylight.controller.samples.loadbalancer.LBConst;
+import org.opendaylight.controller.samples.loadbalancer.LBUtil;
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+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.samples.loadbalancer.policies.RandomLBPolicy;
+import org.opendaylight.controller.samples.loadbalancer.policies.RoundRobinLBPolicy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is the main class that represents the load balancer service. 
+ * This is a sample load balancer application that balances traffic to backend servers 
+ * based on the source address and source port on each incoming packet.  The service 
+ * reactively installs OpenFlow rules to direct all packets with a specific source address
+ * and source port to one of the appropriate backend servers.  The servers may be chosen 
+ * using a round robin policy or a random policy. This service can be configured via a 
+ * REST APIs which are similar to the OpenStack Quantum LBaaS (Load-balancer-as-a-Service)
+ * v1.0 API proposal (http://wiki.openstack.org/Quantum/LBaaS)
+ * 
+ * To use this service, a virtual IP (or VIP) should be exposed to the clients of this service
+ * and used as the destination address. A VIP is a entity that comprises of a virtual IP, port
+ * and protocol (TCP or UDP).
+ * Assumptions:
+ *      1. One or more VIPs may be mapped to the same server pool. All VIPs that share the same
+ *      pool must also share the same load balancing policy (random or round robin).
+ *      
+ *      2. Only one server pool can be be assigned to a VIP.
+ *      
+ *      3. All flow rules are installed with an idle timeout of 5 seconds.
+ *      
+ *      4. Packets to a VIP must leave the OpenFlow  cluster from the same switch from where
+ *      it entered it.
+ *      
+ *      5. When you delete a VIP or a server pool or a server from a pool, the service does not
+ *      delete the flow rules it has already installed. The flow rules should automatically
+ *      time out after the idle timeout of 5 seconds. 
+ *
+ */
+public class LoadBalancerService implements IListenDataPacket, IConfigManager{
+    
+    /*
+     * Logger instance
+     */
+    private static Logger lbsLogger = LoggerFactory.getLogger(LoadBalancerService.class);
+    
+    /*
+     * Single instance of the configuration manager. Application passes this reference to all
+     * the new policies implemented for load balancing.
+     */
+    private static ConfigManager configManager = new ConfigManager();
+    
+    /*
+     * Round robing policy instance. Need to implement factory patterns to get
+     * policy instance.
+     */
+    private static RoundRobinLBPolicy rrLBMethod= new RoundRobinLBPolicy(configManager);
+    
+    /*
+     * Random policy instance.
+     */
+    private static RandomLBPolicy ranLBMethod= new RandomLBPolicy(configManager);
+    
+    /*
+     * Reference to the data packet service
+     */
+    private IDataPacketService dataPacketService = null;
+    
+    /*
+     * Reference to the host tracker service
+     */
+    private IfIptoHost hostTracker;
+    
+    /*
+     * Reference to the forwarding manager
+     */
+    private IForwardingRulesManager ruleManager;
+    
+    /*
+     * Reference to the routing service
+     */
+    private IRouting routing;
+    
+    /*
+     * Load balancer application installs all flows with priority 2.
+     */
+    private static short LB_IPSWITCH_PRIORITY = 2;
+
+    /*
+     * Name of the container where this application will register.
+     */
+    private String containerName = null;
+
+    /*
+     * Set/unset methods for the service instance that load balancer 
+     * service requires
+     */
+    public String getContainerName() {
+        if (containerName == null)
+            return GlobalConstants.DEFAULT.toString();
+        return containerName;
+    }
+    
+    void setDataPacketService(IDataPacketService s) {
+        this.dataPacketService = s;
+    }
+
+    void unsetDataPacketService(IDataPacketService s) {
+        if (this.dataPacketService == s) {
+            this.dataPacketService = null;
+        }
+    }
+    
+    public void setRouting(IRouting routing) {
+        this.routing = routing;
+    }
+
+    public void unsetRouting(IRouting routing) {
+        if (this.routing == routing) {
+            this.routing = null;
+        }
+    }
+
+    public void setHostTracker(IfIptoHost hostTracker) {
+       lbsLogger.debug("Setting HostTracker");
+        this.hostTracker = hostTracker;
+    }
+
+    public void unsetHostTracker(IfIptoHost hostTracker) {
+        if (this.hostTracker == hostTracker) {
+            this.hostTracker = null;
+        }
+    }
+
+    public void setForwardingRulesManager(
+            IForwardingRulesManager forwardingRulesManager) {
+       lbsLogger.debug("Setting ForwardingRulesManager");
+        this.ruleManager = forwardingRulesManager;
+    }
+
+    public void unsetForwardingRulesManager(
+            IForwardingRulesManager forwardingRulesManager) {
+        if (this.ruleManager == forwardingRulesManager) {
+            this.ruleManager = null;
+        }
+    }
+
+    /**
+     * This method receives first packet of flows for which there is no
+     * matching flow rule installed on the switch. IP addresses used for VIPs 
+     * are not supposed to be used by any real/virtual host in the network.
+     * Hence, any forwarding/routing service will not install any flows rules matching
+     * these VIPs. This ensures that all the flows destined for VIPs will not find a match
+     * in the switch and will be forwarded to the load balancing service.
+     * Service will decide where to route this traffic based on the load balancing 
+     * policy of the VIP's attached pool and will install appropriate flow rules 
+     * in a reactive manner. 
+     */
+    @Override
+    public PacketResult receiveDataPacket(RawPacket inPkt){
+        
+        if (inPkt == null) {
+            return PacketResult.IGNORED;
+        }
+        
+        Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
+        
+        if (formattedPak instanceof Ethernet) {
+            byte[] vipMacAddr = ((Ethernet) formattedPak).getDestinationMACAddress();
+            Object ipPkt = formattedPak.getPayload();
+            
+            if (ipPkt instanceof IPv4) {
+                
+                lbsLogger.debug("Packet recieved from switch : {}",inPkt.getIncomingNodeConnector().getNode().toString());
+                IPv4 ipv4Pkt = (IPv4)ipPkt;
+                if(IPProtocols.getProtocolName(ipv4Pkt.getProtocol()).equals(IPProtocols.TCP.toString())
+                        || IPProtocols.getProtocolName(ipv4Pkt.getProtocol()).equals(IPProtocols.TCP.toString())){
+                    
+                    lbsLogger.debug("Packet protocol : {}",IPProtocols.getProtocolName(ipv4Pkt.getProtocol()));
+                    Client client = new LBUtil().getClientFromPacket(ipv4Pkt);
+                    VIP vip = new LBUtil().getVIPFromPacket(ipv4Pkt);
+                    
+                    if(configManager.vipExists(vip)){
+                        VIP vipWithPoolName = configManager.getVIPWithPoolName(vip);
+                        String poolMemberIp = null;
+                        if(configManager.getPool(vipWithPoolName.getPoolName()).getLbMethod().equalsIgnoreCase(LBConst.ROUND_ROBIN_LB_METHOD)){
+                            
+                            poolMemberIp = rrLBMethod.getPoolMemberForClient(client,vipWithPoolName);
+                        }
+                        
+                        if(configManager.getPool(vipWithPoolName.getPoolName()).getLbMethod().equalsIgnoreCase(LBConst.RANDOM_LB_METHOD)){
+                            poolMemberIp = ranLBMethod.getPoolMemberForClient(client,vipWithPoolName);
+                        }
+                        
+                        try {
+                            
+                            Node clientNode = inPkt.getIncomingNodeConnector().getNode();
+                            HostNodeConnector hnConnector = this.hostTracker.hostFind(InetAddress.getByName(poolMemberIp));
+                            
+                            Node destNode = hnConnector.getnodeconnectorNode();
+                            
+                            lbsLogger.debug("Client is connected to switch : {}",clientNode.toString());
+                            lbsLogger.debug("Destination pool machine is connected to switch : {}",destNode.toString());
+                            
+                            //Get path between both the nodes
+                            Path route = this.routing.getRoute(clientNode, destNode);
+                            
+                            lbsLogger.info("Path between source (client) and destination switch nodes : {}",route.toString());
+                            
+                            NodeConnector forwardPort = route.getEdges().get(0).getTailNodeConnector();
+                            
+                            if(installLoadBalancerFlow(client,
+                                                            vip,
+                                                            clientNode,
+                                                            poolMemberIp,
+                                                            hnConnector.getDataLayerAddressBytes(),
+                                                            forwardPort,
+                                                            LBConst.FORWARD_DIRECTION_LB_FLOW)){
+                                lbsLogger.info("Traffic from client : {} will be routed " +
+                                                            "to pool machine : {}",client,poolMemberIp);
+                            }else{
+                                lbsLogger.error("Not able to route traffic from client : {}",client );
+                            }
+                            
+                            if(installLoadBalancerFlow(client,
+                                                            vip,
+                                                            clientNode,
+                                                            poolMemberIp,
+                                                            vipMacAddr,
+                                                            inPkt.getIncomingNodeConnector(),
+                                                            LBConst.REVERSE_DIRECTION_LB_FLOW)){
+                                lbsLogger.info("Flow rule installed to change the source ip/mac from " +
+                                                            "pool machine ip {} to VIP {} for traffic coming pool machine",poolMemberIp,vip);
+                            }else{
+                                lbsLogger.error("Not able to route traffic from client : {}",client );
+                            }
+                        }catch (UnknownHostException e) {
+                            lbsLogger.error("Pool member not found  in the network : {}",e.getMessage());
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            }
+        }
+        return PacketResult.IGNORED;
+    }
+    
+    /*
+     * This method installs the flow rule for routing the traffic between two hosts.
+     * @param source    Traffic is sent by this source
+     * @param dest      Traffic is destined to this destination (VIP)
+     * @param sourceSwitch      Switch from where controller received the packet
+     * @param destMachineIp     IP address of the pool member where traffic needs to be routed
+     * @param destMachineMac    MAC address of the pool member where traffic needs to be routed
+     * @param outport   Use this port to send out traffic
+     * @param flowDirection     FORWARD_DIRECTION_LB_FLOW or REVERSE_DIRECTION_LB_FLOW
+     * @return true     If flow installation was successful
+     *          false  else
+     *          @throws UnknownHostException
+     */
+    private boolean installLoadBalancerFlow(Client source,
+                                            VIP dest,
+                                            Node sourceSwitch,
+                                            String destMachineIp,
+                                            byte[] destMachineMac, 
+                                            NodeConnector outport,
+                                            int flowDirection) throws UnknownHostException{
+        
+        Match match = new Match();
+        List<Action> actions = new ArrayList<Action>();
+        
+        if(flowDirection == LBConst.FORWARD_DIRECTION_LB_FLOW){
+            match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue());
+            match.setField(MatchType.NW_SRC, InetAddress.getByName(source.getIp()));
+            match.setField(MatchType.NW_DST, InetAddress.getByName(dest.getIp()));
+            match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(dest.getProtocol()));
+            match.setField(MatchType.TP_SRC, source.getPort());
+            match.setField(MatchType.TP_DST, dest.getPort());
+            
+            actions.add(new SetNwDst(InetAddress.getByName(destMachineIp)));
+            actions.add(new SetDlDst(destMachineMac));
+        }
+        
+        if(flowDirection == LBConst.REVERSE_DIRECTION_LB_FLOW){
+            match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue());
+            match.setField(MatchType.NW_SRC, InetAddress.getByName(destMachineIp));
+            match.setField(MatchType.NW_DST, InetAddress.getByName(source.getIp()));
+            match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(source.getProtocol()));
+            match.setField(MatchType.TP_SRC, dest.getPort());
+            match.setField(MatchType.TP_DST,source.getPort());
+            
+            actions.add(new SetNwSrc(InetAddress.getByName(dest.getIp())));
+            actions.add(new SetDlSrc(destMachineMac));
+        }
+        
+        actions.add(new Output(outport));
+        
+        // Make sure the priority for IP switch entries is
+        // set to a level just above default drop entries
+        
+        Flow flow = new Flow(match, actions);
+        flow.setIdleTimeout((short) 5);
+        flow.setHardTimeout((short) 0);
+        flow.setPriority(LB_IPSWITCH_PRIORITY);
+        
+        String policyName = source.getIp()+":"+source.getProtocol()+":"+source.getPort();
+        String flowName =null;
+        
+        if(flowDirection == LBConst.FORWARD_DIRECTION_LB_FLOW){
+            flowName = "["+policyName+":"+source.getIp() + ":"+dest.getIp()+"]";
+        }
+        
+        if(flowDirection == LBConst.REVERSE_DIRECTION_LB_FLOW){
+            
+            flowName = "["+policyName+":"+dest.getIp() + ":"+source.getIp()+"]";
+        }
+        
+        FlowEntry fEntry = new FlowEntry(policyName, flowName, flow, sourceSwitch);
+        
+        lbsLogger.info("Install flow entry {} on node {}",fEntry.toString(),sourceSwitch.toString());
+        
+        if(!this.ruleManager.checkFlowEntryConflict(fEntry)){
+            if(this.ruleManager.installFlowEntry(fEntry).isSuccess()){
+                return true;
+            }else{
+                lbsLogger.error("Error in installing flow entry to node : {}",sourceSwitch);
+            }
+        }else{
+            lbsLogger.error("Conflicting flow entry exists : {}",fEntry.toString());
+        }
+        return false;
+    }
+    
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init(Component c) {
+        Dictionary<?, ?> props = c.getServiceProperties();
+        if (props != null) {
+            this.containerName = (String) props.get("containerName");
+            
+            lbsLogger.info("Running container name:" + this.containerName);
+        }else {
+            
+            // In the Global instance case the containerName is empty
+            this.containerName = "";
+        }
+        lbsLogger.info(configManager.toString());
+    }
+    
+    /**
+     * Function called by the dependency manager when at least one
+     * dependency become unsatisfied or when the component is shutting
+     * down because for example bundle is being stopped.
+     *
+     */
+    void destroy() {
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called
+     * and after the services provided by the class are registered in
+     * the service registry
+     *
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services
+     * exported by the component are unregistered, this will be
+     * followed by a "destroy ()" calls
+     *
+     */
+    void stop() {
+    }
+
+    /*
+     * All the methods below are just proxy methods to direct the REST API requests to configuration
+     * manager. We need this redirection as currently, opendaylight supports only one 
+     * implementation of the service. 
+     */
+    @Override
+    public Set<VIP> getAllVIPs() {
+        return configManager.getAllVIPs();
+    }
+    
+    @Override
+    public boolean vipExists(String name, String ip, String protocol,
+                                short protocolPort, String poolName) {
+        return configManager.vipExists(name, ip, protocol, protocolPort, poolName);
+    }
+    
+    @Override
+    public boolean vipExists(VIP vip) {
+        return configManager.vipExists(vip);
+    }
+    
+    @Override
+    public VIP createVIP(String name, String ip, String protocol,
+                            short protocolPort, String poolName) {
+        return configManager.createVIP(name, ip, protocol, protocolPort, poolName);
+    }
+    
+    @Override
+    public VIP updateVIP(String name, String poolName) {
+        return configManager.updateVIP(name, poolName);
+    }
+    
+    @Override
+    public VIP deleteVIP(String name) {
+        return configManager.deleteVIP(name);
+    }
+    
+    @Override
+    public boolean memberExists(String name, String memberIP, String poolName) {
+        return configManager.memberExists(name, memberIP, poolName);
+    }
+    
+    @Override
+    public Set<PoolMember> getAllPoolMembers(String poolName) {
+        
+        return configManager.getAllPoolMembers(poolName);
+    }
+    
+    @Override
+    public PoolMember addPoolMember(String name, 
+                                    String memberIP,
+                                    String poolName) {
+        return configManager.addPoolMember(name, memberIP, poolName);
+    }
+    
+    @Override
+    public PoolMember removePoolMember(String name, String poolName) {
+        
+        return configManager.removePoolMember(name, poolName);
+    }
+    
+    @Override
+    public Set<Pool> getAllPools() {
+        
+        return configManager.getAllPools();
+    }
+    
+    @Override
+    public Pool getPool(String poolName) {
+        return configManager.getPool(poolName);
+    }
+    
+    @Override
+    public boolean poolExists(String name, String lbMethod) {
+        return configManager.poolExists(name, lbMethod);
+    }
+    
+    @Override
+    public Pool createPool(String name, String lbMethod) {
+        return configManager.createPool(name, lbMethod);
+    }
+    
+    @Override
+    public Pool deletePool(String poolName) {
+        return configManager.deletePool(poolName);
+    }
+    
+    @Override
+    public boolean vipExists(String name) {
+        return configManager.vipExists(name);
+    }
+    
+    @Override
+    public boolean memberExists(String name, String poolName) {
+        return configManager.memberExists(name, poolName);
+    }
+    
+    @Override
+    public boolean poolExists(String name) {
+        return configManager.poolExists(name);
+    }
+    
+    @Override
+    public String getVIPAttachedPool(String name) {
+        return configManager.getVIPAttachedPool(name);
+    }
+}
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/ILoadBalancingPolicy.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/ILoadBalancingPolicy.java
new file mode 100644 (file)
index 0000000..d69c63c
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.policies;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+
+/**
+ * All new load balancer policies must implement this interface.
+ */
+public interface ILoadBalancingPolicy {
+    
+    /**
+     * Returns IP address of the next pool member from the pool
+     * to which the load balancer service can direct incoming packets.
+     * @param source    source on the packet
+     * @param dest      virtual IP (VIP) that is used as destination on the packet
+     * @return IP address of the next pool member which will serve
+     *          all incoming traffic destined for the given VIP and with the given source
+     *          information
+     */
+    public String getPoolMemberForClient(Client source, VIP dest);
+    
+}
\ No newline at end of file
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/RandomLBPolicy.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/RandomLBPolicy.java
new file mode 100644 (file)
index 0000000..b4b616f
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.policies;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Random;
+
+import org.opendaylight.controller.samples.loadbalancer.ConfigManager;
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements the random load balancing policy.
+ *
+ */
+public class RandomLBPolicy implements ILoadBalancingPolicy {
+    
+    /*
+     * Instance logger
+     */
+    private static final Logger rLogger = LoggerFactory.getLogger(RandomLBPolicy.class);
+    
+    /*
+     * Reference to the configuration manager. This reference is passed from load balancer 
+     * class.
+     */
+    private ConfigManager cmgr;
+    
+    /*
+     * Mapping between the client and the pool member that serves all traffic for that client.
+     */
+    private HashMap<Client, PoolMember> clientMemberMap;
+    
+    /*
+     * Random generator
+     */
+    Random randomGenerator = null;
+    
+    @SuppressWarnings("unused")
+    private RandomLBPolicy(){}
+    
+    public RandomLBPolicy(ConfigManager cmgr){
+        this.cmgr = cmgr;
+        this.clientMemberMap = new HashMap<Client, PoolMember>();
+        randomGenerator = new Random();
+    }
+    @Override
+    public String getPoolMemberForClient(Client source, VIP dest){
+        
+        rLogger.info("Received traffic from client : {} for VIP : {} ",source, dest);
+        
+        syncWithLoadBalancerData();
+        
+        PoolMember pm= null;
+        
+        if(this.clientMemberMap.containsKey(source)){
+            pm= this.clientMemberMap.get(source);
+            rLogger.info("Client {} had sent traffic before,new traffic will be routed to the same pool member {}",source,pm);
+        }else{
+            Pool pool = null;
+            pool = this.cmgr.getPool(dest.getPoolName());
+            int memberNum = this.randomGenerator.nextInt(pool.getAllMembers().size()-1);
+            pm = pool.getAllMembers().get(memberNum);
+            this.clientMemberMap.put(source, pm );
+            rLogger.info("Network traffic from client {} will be directed to pool member {}",pm);
+        }
+        return pm.getIp();
+    }
+    
+    /*
+     * This method does the clean up. Whenever a new client packet arrives with a given VIP,
+     * this method checks the current configuration to see if any pool members have been deleted and
+     * cleans up the metadata stored by this loadbalancing algorithm.
+     */
+    private void syncWithLoadBalancerData(){
+        rLogger.debug("[Client - PoolMember] table before cleanup : {}",this.clientMemberMap.toString());
+        
+        ArrayList<Client> removeClient = new ArrayList<Client>();
+        
+        if(this.clientMemberMap.size() != 0){
+            for(Client client : this.clientMemberMap.keySet()){
+                
+                if(!this.cmgr.memberExists(this.clientMemberMap.get(client).getName(),
+                                                this.clientMemberMap.get(client).getPoolName())){
+                    removeClient.add(client);
+                }
+            }
+        }
+        
+        for(Client client : removeClient){
+            this.clientMemberMap.remove(client);
+            
+            rLogger.debug("Removed client : {} ",client);
+        }
+        rLogger.debug("[Client - PoolMember] table after cleanup : {}",this.clientMemberMap.toString());
+    }
+    
+}
diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/RoundRobinLBPolicy.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/policies/RoundRobinLBPolicy.java
new file mode 100644 (file)
index 0000000..f1011dd
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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.policies;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.opendaylight.controller.samples.loadbalancer.ConfigManager;
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements the round robin load balancing policy.
+ *
+ */
+public class RoundRobinLBPolicy implements ILoadBalancingPolicy{
+    
+    /*
+     * Logger instance
+     */
+    private static final Logger rrLogger = LoggerFactory.getLogger(RoundRobinLBPolicy.class);
+    
+    /*
+     * Reference to the configuration manager. This reference is passed from load balancer 
+     * class.
+     */
+    private ConfigManager cmgr;
+    
+    /*
+     * Mapping between the client and the pool member that serves all traffic for that client.
+     */
+    private HashMap<Client, PoolMember> clientMemberMap;
+    
+    /*
+     * Maintains the next pool member counter for the VIPs.
+     * More than one VIP can be attached to one pool, so each VIP
+     * will have its own counter for the next pool member from
+     * the same pool.
+     */
+    private HashMap<VIP,Integer> nextItemFromPool;
+    
+    @SuppressWarnings("unused")
+    private RoundRobinLBPolicy(){}
+    
+    public RoundRobinLBPolicy(ConfigManager cmgr){
+        this.cmgr = cmgr;
+        this.clientMemberMap = new HashMap<Client, PoolMember>();
+        this.nextItemFromPool = new HashMap<VIP, Integer>();
+    }
+    
+    @Override
+    public String getPoolMemberForClient(Client source, VIP dest){
+        
+        rrLogger.info("Received traffic from client : {} for VIP : {} ",source, dest);
+        
+        syncWithLoadBalancerData();
+        
+        PoolMember pm= null;
+        
+        if(this.clientMemberMap.containsKey(source)){
+            
+            pm= this.clientMemberMap.get(source);
+            rrLogger.info("Client {} had sent traffic before,new traffic will be routed to the same pool member {}",source,pm);
+        }else{
+            
+            Pool pool = null;
+            if(nextItemFromPool.containsKey(dest)){
+                
+                int memberNum = nextItemFromPool.get(dest).intValue();
+                rrLogger.debug("Packet is from new client for VIP {}",dest);
+                pool = this.cmgr.getPool(dest.getPoolName());
+                pm = pool.getAllMembers().get(memberNum);
+                this.clientMemberMap.put(source, pm );
+                rrLogger.info("New client's packet will be directed to pool member {}",pm);
+                memberNum++;
+                
+                if(memberNum > pool.getAllMembers().size()-1){
+                    memberNum = 0;
+                }
+                rrLogger.debug("Next pool member for new client of VIP is set to {}",pool.getAllMembers().get(memberNum));
+                
+                this.nextItemFromPool.put(dest, new Integer(memberNum));
+            }else{
+                rrLogger.debug("Network traffic for VIP : {} has appeared first time from client {}",dest,source);
+                pool = this.cmgr.getPool(dest.getPoolName());
+                pm = pool.getAllMembers().get(0);
+                this.clientMemberMap.put(source, pm);
+                
+                rrLogger.info("Network traffic from client {} will be directed to pool member {}",pm);
+                this.nextItemFromPool.put(dest, new Integer(1));
+                rrLogger.debug("Next pool member for new client of VIP is set to {}",pool.getAllMembers().get(1));
+            }
+        }
+        return pm.getIp();
+    }
+    
+    /*
+     * This method does the clean up. Whenever a new client packet arrives with a given VIP,
+     * this method checks the current configuration to see if any pool members have been deleted and
+     * cleans up the metadata stored by this loadbalancing algorithm.
+     */
+    private void syncWithLoadBalancerData(){
+        rrLogger.debug("[Client - PoolMember] table before cleanup : {}",this.clientMemberMap.toString());
+        ArrayList<Client> removeClient = new ArrayList<Client>();
+        
+        if(this.clientMemberMap.size() != 0){
+            for(Client client : this.clientMemberMap.keySet()){
+                if(!this.cmgr.memberExists(this.clientMemberMap.get(client).getName(),
+                                            this.clientMemberMap.get(client).getPoolName())){
+                    
+                    removeClient.add(client);
+                }
+            }
+        }
+        
+        for(Client client : removeClient){
+            this.clientMemberMap.remove(client);
+            
+            rrLogger.debug("Removed client : {} ",client);
+        }
+        rrLogger.debug("[Client - PoolMember] table after cleanup : {}",this.clientMemberMap.toString());
+        
+        rrLogger.debug("[VIP- NextMember] table before cleanup : {}",this.nextItemFromPool.toString());
+        
+        ArrayList<VIP> resetVIPPoolMemberCount= new ArrayList<VIP>();
+        
+        if(this.nextItemFromPool.size() != 0){
+            
+            for(VIP vip:this.nextItemFromPool.keySet()){
+                if(this.nextItemFromPool.get(vip).intValue() > this.cmgr.getPool(vip.getPoolName()).getAllMembers().size()-1){
+                    
+                    resetVIPPoolMemberCount.add(vip);
+                }
+            }
+        }
+        
+        for(VIP vip:resetVIPPoolMemberCount){
+            rrLogger.debug("VIP next pool member counter reset to 0");
+            this.nextItemFromPool.put(vip, new Integer(0));
+        }
+        
+        rrLogger.debug("[VIP- NextMember] table after cleanup : {}",this.nextItemFromPool.toString());
+    }
+}
diff --git a/opendaylight/samples/loadbalancer/src/test/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerTest.java b/opendaylight/samples/loadbalancer/src/test/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerTest.java
new file mode 100644 (file)
index 0000000..f8633b9
--- /dev/null
@@ -0,0 +1,69 @@
+/*\r
+ * Copyright IBM Corporation, 2013.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.samples.loadbalancer.internal;\r
+\r
+\r
+import org.junit.Assert;\r
+import org.junit.Test;\r
+import org.opendaylight.controller.samples.loadbalancer.ConfigManager;\r
+import org.opendaylight.controller.samples.loadbalancer.entities.Client;\r
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;\r
+import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;\r
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;\r
+import org.opendaylight.controller.samples.loadbalancer.policies.RoundRobinLBPolicy;\r
+\r
+import junit.framework.TestCase;\r
+\r
+/**\r
+ * \r
+ * Class to unit test the load balancing policies.\r
+ *\r
+ */\r
+public class LoadBalancerTest extends TestCase {\r
+    @Test\r
+    public void testRoundRobinPolicy() {\r
+        ConfigManager cm = null;\r
+        cm = new ConfigManager();\r
+        Assert.assertFalse(cm== null);\r
+        \r
+        Pool pool = cm.createPool("TestPool","roundrobin");\r
+        VIP vip = cm.createVIP("TestVIP","10.0.0.9","TCP",(short)5550,"TestPool");\r
+        PoolMember host1 = new PoolMember("host1","10.0.0.1","TestPool");\r
+        PoolMember host2 = new PoolMember("host2","10.0.0.2","TestPool");\r
+        PoolMember host3 = new PoolMember("host3","10.0.0.3","TestPool");\r
+        PoolMember host4 = new PoolMember("host4","10.0.0.4","TestPool");\r
+        PoolMember host5 = new PoolMember("host5","10.0.0.5","TestPool");\r
+        PoolMember host6 = new PoolMember("host6","10.0.0.6","TestPool");\r
+        PoolMember host7 = new PoolMember("host7","10.0.0.7","TestPool");\r
+        \r
+        pool.addMember(host1);\r
+        pool.addMember(host2);\r
+        pool.addMember(host3);\r
+        pool.addMember(host4);\r
+        pool.addMember(host5);\r
+        pool.addMember(host6);\r
+        pool.addMember(host7);\r
+        pool.addVIP(vip);\r
+        \r
+        Assert.assertTrue(cm.getAllPoolMembers("TestPool").size() == pool.getAllMembers().size());\r
+        \r
+        RoundRobinLBPolicy rrp = new RoundRobinLBPolicy(cm);\r
+        \r
+        Client c1 = new Client("10.0.0.1","TCP",(short)5000);\r
+        Assert.assertTrue(rrp.getPoolMemberForClient(c1, vip).equals(host1.getIp()));\r
+        \r
+        c1 = new Client("10.0.0.1","TCP",(short)5001);\r
+        Assert.assertTrue(rrp.getPoolMemberForClient(c1, vip).equals(host2.getIp()));\r
+        \r
+        c1 = new Client("10.0.0.1","TCP",(short)5002);\r
+        Assert.assertTrue(rrp.getPoolMemberForClient(c1, vip).equals(host3.getIp()));\r
+        \r
+        c1 = new Client("10.0.0.1","TCP",(short)5003);\r
+        Assert.assertTrue(rrp.getPoolMemberForClient(c1, vip).equals(host4.getIp()));\r
+    }\r
+}
\ No newline at end of file
diff --git a/opendaylight/samples/northbound/loadbalancer/enunciate.xml b/opendaylight/samples/northbound/loadbalancer/enunciate.xml
new file mode 100644 (file)
index 0000000..e666af7
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.26.xsd">
+  
+  <services>
+    <rest defaultRestSubcontext="/one/nb/v2/lb"/>
+  </services>
+
+  <modules>
+    <docs docsDir="rest" title="Load Balancer REST API" includeExampleXml="true" includeExampleJson="true"/>
+  </modules>
+</enunciate>
diff --git a/opendaylight/samples/northbound/loadbalancer/pom.xml b/opendaylight/samples/northbound/loadbalancer/pom.xml
new file mode 100644 (file)
index 0000000..2b9b1c4
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath>../../../commons/opendaylight</relativePath>
+  </parent>
+  <groupId>org.opendaylight.controller</groupId>
+  <artifactId>samples.loadbalancer.northbound</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.enunciate</groupId>
+        <artifactId>maven-enunciate-plugin</artifactId>
+        <version>${enunciate.version}</version>
+        <dependencies>
+          <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal</artifactId>
+            <version>0.4.0-SNAPSHOT</version>
+          </dependency>
+        </dependencies>
+      </plugin>    
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>
+                               org.opendaylight.controller.samples.loadbalancer,
+                               org.opendaylight.controller.samples.loadbalancer.entities,
+                               org.opendaylight.controller.samples.loadbalancer.internal,
+                               org.opendaylight.controller.samples.loadbalancer.policies,
+                               org.opendaylight.controller.hosttracker,
+                               org.opendaylight.controller.sal.core,
+                               org.opendaylight.controller.sal.utils,
+                               org.opendaylight.controller.containermanager,
+                               org.opendaylight.controller.switchmanager,
+                               org.apache.commons.logging,
+                               com.sun.jersey.spi.container.servlet,
+                               org.opendaylight.controller.northbound.commons,
+                               org.opendaylight.controller.northbound.commons.exception,
+                               com.sun.jersey.spi.spring.container.servlet,
+                               org.springframework.web.context,
+                               org.springframework.web,
+                               org.springframework.web.servlet,
+                               org.springframework.web.filter,
+                               org.springframework.security.config,
+                               org.springframework.security.web.authentication,
+                               org.springframework.security.web.authentication.www,
+                               javax.ws.rs,
+                               javax.ws.rs.core,
+                               javax.xml.bind.annotation,
+                               javax.xml.bind,
+                               org.slf4j,
+                               !org.codehaus.enunciate.jaxrs
+            </Import-Package>
+            <Web-ContextPath>/one/nb/v2/lb</Web-ContextPath>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller.thirdparty</groupId>
+      <artifactId>com.sun.jersey.jersey-servlet</artifactId>
+      <version>1.17-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>containermanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>hosttracker</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>samples.loadbalancer</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+       <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+       </dependency> 
+    <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+         <artifactId>commons.northbound</artifactId>
+         <version>0.4.0-SNAPSHOT</version>
+       </dependency>
+    <dependency>
+      <groupId>org.codehaus.enunciate</groupId>
+      <artifactId>enunciate-core-annotations</artifactId>
+      <version>${enunciate.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthbound.java b/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthbound.java
new file mode 100644 (file)
index 0000000..4ec567c
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * 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 javax.xml.bind.JAXBElement;
+
+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) JAXBElement<VIP> inVIP){
+        
+        VIP vipInput = inVIP.getValue();
+        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) JAXBElement<VIP> inVIP) {
+        
+        VIP vipInput = inVIP.getValue();
+        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) JAXBElement<Pool> inPool) {
+        
+        Pool poolInput = inPool.getValue();
+        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) JAXBElement<PoolMember> inPoolMember){
+        
+        PoolMember pmInput = inPoolMember.getValue();
+       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);
+    }
+}
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthboundRSApplication.java b/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthboundRSApplication.java
new file mode 100644 (file)
index 0000000..0c17c84
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.HashSet;
+import java.util.Set;
+import javax.ws.rs.core.Application;
+
+/**
+ * This class is an instance of javax.ws.rs.core.Application and is used to return the classes
+ * that will be instantiated for JAXRS processing. This is necessary
+ * because package scanning in jersey doesn't yet work in OSGi environment.
+ *
+ */
+public class LoadBalancerNorthboundRSApplication extends Application {
+    @Override
+    public Set<Class<?>> getClasses() {
+        Set<Class<?>> classes = new HashSet<Class<?>>();
+        classes.add(LoadBalancerNorthbound.class);
+        return classes;
+    }
+}
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/NBConst.java b/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/NBConst.java
new file mode 100644 (file)
index 0000000..4aa4705
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * This class defines all the constants used by the load balancer north bound service
+ *
+ */
+public class NBConst {
+    
+    public static final String RES_VIP_ALREADY_EXIST= " VIP already exists";
+    
+    public static final String RES_VIP_NOT_FOUND= " VIP not found";
+    
+    public static final String RES_VIP_CREATION_FAILED = " Creation of VIP failed";
+    
+    public static final String RES_VIP_DELETION_FAILED = " Deletion of VIP failed";
+    
+    public static final String RES_VIP_UPDATE_FAILED = " Update of VIP failed";
+    
+    public static final String RES_POOL_ALREADY_EXIST= " Pool already exists";
+    
+    public static final String RES_POOL_NOT_FOUND= " Pool not found";
+    
+    public static final String RES_POOL_CREATION_FAILED = " Creation of pool failed";
+    
+    public static final String RES_POOL_DELETION_FAILED = " Deletion of pool failed";
+    
+    public static final String RES_POOLMEMBER_ALREADY_EXIST= " Pool member already exists";
+    
+    public static final String RES_POOLMEMBER_NOT_FOUND= " Pool member not found";
+    
+    public static final String RES_POOLMEMBER_CREATION_FAILED = " Creation of pool member failed";
+    
+    public static final String RES_POOLMEMBER_DELETION_FAILED = " Deletion of pool member failed";
+    
+    public static final String RES_VIP_POOL_EXIST = "Pool already attached to a VIP";
+}
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/Pools.java b/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/Pools.java
new file mode 100644 (file)
index 0000000..abb5495
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.Set;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+/**
+ * JAX-RS resource for handling details of all the available pools 
+ * in response to respective REST API requests.
+ */
+
+public class Pools {
+    
+    @XmlElement (name="pool")
+    Set<Pool> loadBalancerPools;
+    
+    public Pools() {
+    }
+    
+    public Pools (Set<Pool> loadBalancerPools) {
+        this.loadBalancerPools = loadBalancerPools;
+    }
+    
+    /**
+     * @return the loadBalancerPools
+     */
+    public Set<Pool> getLoadBalancerPools() {
+        return loadBalancerPools;
+    }
+    
+    /**
+     * @param loadBalancerPools the loadBalancerPools to set
+     */
+    public void setLoadBalancerPools(Set<Pool> loadBalancerPools) {
+        this.loadBalancerPools = loadBalancerPools;
+    }
+}
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/VIPs.java b/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/VIPs.java
new file mode 100644 (file)
index 0000000..f0af929
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.Set;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
+
+/**
+ * JAX-RS resource for handling details of all the available VIPs
+ * in response to respective REST API requests.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class VIPs {
+    
+    @XmlElement (name="vip")
+    Set<VIP> loadBalancerVIPs;
+    
+    public VIPs() {}
+    
+    
+    public VIPs (Set<VIP> loadBalancerVIPs) {
+        this.loadBalancerVIPs = loadBalancerVIPs;
+    }
+    
+    /**
+     * @return the loadBalancerVIPs
+     */
+    public Set<VIP> getLoadBalancerVIPs() {
+        return loadBalancerVIPs;
+    }
+    
+    /**
+     * @param loadBalancerVIPs the loadBalancerVIPs to set
+     */
+    
+    public void setLoadBalancerVIPs(Set<VIP> loadBalancerVIPs) {
+        this.loadBalancerVIPs = loadBalancerVIPs;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.factories b/opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.factories
new file mode 100644 (file)
index 0000000..93db02e
--- /dev/null
@@ -0,0 +1 @@
+org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.handlers b/opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.handlers
new file mode 100644 (file)
index 0000000..957af91
--- /dev/null
@@ -0,0 +1,10 @@
+http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
+http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
+http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
+http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
+http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
+http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
+http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
+http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
+http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
+http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.schemas b/opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.schemas
new file mode 100644 (file)
index 0000000..d865edc
--- /dev/null
@@ -0,0 +1,49 @@
+http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
+http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
+http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
+http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
+http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd
+http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd
+http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
+http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
+http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
+http\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd
+http\://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
+http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
+http\://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd
+http\://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd
+http\://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd
+http\://www.springframework.org/schema/context/spring-context-3.2.xsd=org/springframework/context/config/spring-context-3.2.xsd
+http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-3.2.xsd
+http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd
+http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.1.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.2.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd
+http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd
+http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd
+http\://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.2.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
+http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
+http\://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd
+http\://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd
+http\://www.springframework.org/schema/task/spring-task-3.2.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
+http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
+http\://www.springframework.org/schema/cache/spring-cache-3.1.xsd=org/springframework/cache/config/spring-cache-3.1.xsd
+http\://www.springframework.org/schema/cache/spring-cache-3.2.xsd=org/springframework/cache/config/spring-cache-3.2.xsd
+http\://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache-3.2.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd=org/springframework/web/servlet/config/spring-mvc-3.0.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd=org/springframework/web/servlet/config/spring-mvc-3.1.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd=org/springframework/web/servlet/config/spring-mvc-3.2.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc.xsd=org/springframework/web/servlet/config/spring-mvc-3.2.xsd
+http\://www.springframework.org/schema/security/spring-security-3.1.xsd=org/springframework/security/config/spring-security-3.1.xsd
+http\://www.springframework.org/schema/security/spring-security-3.2.xsd=org/springframework/security/config/spring-security-3.2.xsd
+
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.tooling b/opendaylight/samples/northbound/loadbalancer/src/main/resources/META-INF/spring.tooling
new file mode 100644 (file)
index 0000000..057d834
--- /dev/null
@@ -0,0 +1,39 @@
+# Tooling related information for the beans namespace
+http\://www.springframework.org/schema/beans@name=beans Namespace
+http\://www.springframework.org/schema/beans@prefix=beans
+http\://www.springframework.org/schema/beans@icon=org/springframework/beans/factory/xml/spring-beans.gif
+
+# Tooling related information for the util namespace
+http\://www.springframework.org/schema/util@name=util Namespace
+http\://www.springframework.org/schema/util@prefix=util
+http\://www.springframework.org/schema/util@icon=org/springframework/beans/factory/xml/spring-util.gif
+
+# Tooling related information for the context namespace
+http\://www.springframework.org/schema/context@name=context Namespace
+http\://www.springframework.org/schema/context@prefix=context
+http\://www.springframework.org/schema/context@icon=org/springframework/context/config/spring-context.gif
+
+# Tooling related information for the jee namespace
+http\://www.springframework.org/schema/jee@name=jee Namespace
+http\://www.springframework.org/schema/jee@prefix=jee
+http\://www.springframework.org/schema/jee@icon=org/springframework/ejb/config/spring-jee.gif
+
+# Tooling related information for the scheduling namespace
+http\://www.springframework.org/schema/task@name=task Namespace
+http\://www.springframework.org/schema/task@prefix=task
+http\://www.springframework.org/schema/task@icon=org/springframework/scheduling/config/spring-task.gif
+
+# Tooling related information for the lang namespace
+http\://www.springframework.org/schema/lang@name=lang Namespace
+http\://www.springframework.org/schema/lang@prefix=lang
+http\://www.springframework.org/schema/lang@icon=org/springframework/scripting/config/spring-lang.gif
+
+# Tooling related information for the cache namespace
+http\://www.springframework.org/schema/cache@name=cache Namespace
+http\://www.springframework.org/schema/cache@prefix=cache
+http\://www.springframework.org/schema/cache@icon=org/springframework/cache/config/spring-cache.gif
+
+# Tooling related information for the mvc namespace
+http\://www.springframework.org/schema/mvc@name=mvc Namespace
+http\://www.springframework.org/schema/mvc@prefix=mvc
+http\://www.springframework.org/schema/mvc@icon=org/springframework/web/servlet/config/spring-mvc.gif
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/spring/context.xml b/opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/spring/context.xml
new file mode 100644 (file)
index 0000000..8a4bda5
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns:context="http://www.springframework.org/schema/context"
+  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+        <import resource="servlet/security.xml"/>
+
+</beans>
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/spring/servlet/security.xml b/opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/spring/servlet/security.xml
new file mode 100644 (file)
index 0000000..bce59ee
--- /dev/null
@@ -0,0 +1,36 @@
+<beans:beans xmlns="http://www.springframework.org/schema/security"
+       xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.springframework.org/schema/security
+           http://www.springframework.org/schema/security/spring-security-3.1.xsd">
+
+       <http auto-config="false" authentication-manager-ref="authenticationManager"
+               security-context-repository-ref="securityContextRepo" entry-point-ref="authenticationEntryPoint">
+               <intercept-url pattern="/**"
+                       access="ROLE_SYSTEM-ADMIN, ROLE_NETWORK-ADMIN, ROLE_NETWORK-OPERATOR, ROLE_CONTAINER-USER" />
+               <custom-filter ref="restAuthenticationFilter" position="BASIC_AUTH_FILTER" />
+       </http>
+
+       <authentication-manager id="authenticationManager">
+               <authentication-provider ref="AuthenticationProviderWrapper" />
+       </authentication-manager>
+
+       <beans:bean id="restAuthenticationFilter"
+         class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
+         <beans:property name="authenticationManager" ref="authenticationManager"/>
+         <beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
+       </beans:bean>
+       
+       <beans:bean id="authenticationEntryPoint"
+         class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
+         <beans:property name="realmName" value="opendaylight"/>
+       </beans:bean>
+
+       <beans:bean id="securityContextRepo"
+               class="org.opendaylight.controller.northbound.commons.WebSecurityContextRepository" />
+
+       <beans:bean id="AuthenticationProviderWrapper"
+               class="org.opendaylight.controller.northbound.commons.AuthenticationProviderWrapper" />
+
+</beans:beans>
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/web.xml b/opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..5011e74
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
+http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+  version="2.4">
+  <servlet>
+    <servlet-name>JAXRSLoadBalancer</servlet-name>
+    <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
+    <init-param>
+      <param-name>javax.ws.rs.Application</param-name>
+      <param-value>org.opendaylight.controller.samples.loadbalancer.northbound.LoadBalancerNorthboundRSApplication</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>JAXRSLoadBalancer</servlet-name>
+    <url-pattern>/*</url-pattern>
+  </servlet-mapping>
+
+<!-- Spring Security related -->
+
+       <listener>
+       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+       </listener>
+
+       <context-param>
+               <param-name>contextConfigLocation</param-name>
+               <param-value>/WEB-INF/spring/*.xml</param-value>
+       </context-param>
+
+       <filter>
+           <filter-name>springSecurityFilterChain</filter-name>
+           <filter-class>
+               org.springframework.web.filter.DelegatingFilterProxy
+           </filter-class>
+       </filter>
+       
+       <filter-mapping>
+           <filter-name>springSecurityFilterChain</filter-name>
+           <url-pattern>/*</url-pattern>
+       </filter-mapping>
+</web-app>
index 51e8ea9663289e11cbbb1daaeb6938416871560d..d517c7f7d4a02bd1fd16b96d8ac455fcc6e94b1d 100644 (file)
@@ -371,6 +371,9 @@ one.main.menu = {
 
 one.main.page = {
     load : function(page) {
+               if (one.f !== undefined && one.f.cleanUp !== undefined) {
+                   one.f.cleanUp();
+               }       
         // clear page related
         delete one.f;
         $('.dashlet', '#main').empty();