Squashed commit of the following:
[ovsdb.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / LBaaSPoolMemberHandler.java
index b51cb644357552836be216159b1bc85462d78b25..cb71f389cdf51ea13868e638f16111dd5a949a59 100755 (executable)
@@ -7,21 +7,22 @@
  *
  * Authors : Srini Seetharaman
  */
-
 package org.opendaylight.ovsdb.openstack.netvirt;
 
-import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerCRUD;
-import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberAware;
-import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
-import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
-import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
-import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
-import org.opendaylight.controller.sal.core.Node;
-import org.opendaylight.controller.switchmanager.ISwitchManager;
+import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
+import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
+import org.opendaylight.neutron.spi.INeutronPortCRUD;
+import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
+import org.opendaylight.neutron.spi.NeutronLoadBalancer;
+import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
+import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,6 +30,7 @@ import com.google.common.base.Preconditions;
 
 import java.net.HttpURLConnection;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for
@@ -44,80 +46,108 @@ public class LBaaSPoolMemberHandler extends AbstractHandler
     private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
     private volatile INeutronLoadBalancerCRUD neutronLBCache;
     private volatile INeutronPortCRUD neutronPortsCache;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile INeutronSubnetCRUD neutronSubnetCache;
     private volatile LoadBalancerProvider loadBalancerProvider;
-    private volatile ISwitchManager switchManager;
+    private volatile NodeCacheManager nodeCacheManager;
 
     @Override
     public int canCreateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLBPoolMember);
-        if (lbConfig == null)
+        if (lbConfig == null) {
             return HttpURLConnection.HTTP_BAD_REQUEST;
-        else if (!lbConfig.isValid())
+        } else if (!lbConfig.isValid()) {
             return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
-        else
+        } else {
             return HttpURLConnection.HTTP_OK;
+        }
     }
 
-    /**
-     * Assuming that the pool information is fully populated before this call is made,
-     * we go with creating the LoadBalancerConfiguration object for this call with
-     * all information that is necessary to insert flow_mods
-     */
     @Override
     public void neutronLoadBalancerPoolMemberCreated(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
         logger.debug("Neutron LB Pool Member Creation : {}", neutronLBPoolMember.toString());
         enqueueEvent(new NorthboundEvent(neutronLBPoolMember, Action.ADD));
     }
 
+    /**
+     * Assuming that the pool information is fully populated before this call is made,
+     * we go with creating the LoadBalancerConfiguration object for this call with
+     * all information that is necessary to insert flow_mods
+     */
     private void doNeutronLoadBalancerPoolMemberCreate(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
         Preconditions.checkNotNull(loadBalancerProvider);
         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLBPoolMember);
+        final List<Node> nodes =
+                nodeCacheManager.getBridgeNodes();
         if (lbConfig == null) {
-            logger.trace("Neutron LB configuration invalid for member {} ", neutronLBPoolMember.getPoolMemberAddress());
-        }
-        else if (!lbConfig.isValid()) {
-            logger.trace("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+            logger.debug("Neutron LB configuration invalid for member {} ", neutronLBPoolMember.getPoolMemberAddress());
+        } else if (lbConfig.getVip() == null) {
+            logger.debug("Neutron LB VIP not created yet for member {} ", neutronLBPoolMember.getPoolMemberID());
+        } else if (!lbConfig.isValid()) {
+            logger.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+        } else if (nodes.isEmpty()) {
+            logger.debug("Noop with LB pool member {} creation because no nodes available.", neutronLBPoolMember.getPoolMemberID());
         } else {
-            for (Node node: this.switchManager.getNodes())
-                loadBalancerProvider.programLoadBalancerPoolMemberRules(node, lbConfig,
+            for (Node node : nodes) {
+                loadBalancerProvider.programLoadBalancerPoolMemberRules(node,
+                        lbConfig,
                         lbConfig.getMembers().get(neutronLBPoolMember.getPoolMemberID()), Action.ADD);
+            }
         }
     }
 
     @Override
     public int canUpdateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember delta, NeutronLoadBalancerPoolMember original) {
-        return HttpURLConnection.HTTP_OK;
+        return HttpURLConnection.HTTP_NOT_IMPLEMENTED;
     }
 
     @Override
     public void neutronLoadBalancerPoolMemberUpdated(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        logger.debug("Neutron LB Pool Member Update : {}", neutronLBPoolMember.toString());
         enqueueEvent(new NorthboundEvent(neutronLBPoolMember, Action.UPDATE));
-        return;
     }
 
     @Override
     public int canDeleteNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLBPoolMember);
-        if (lbConfig == null)
+        if (lbConfig == null) {
             return HttpURLConnection.HTTP_BAD_REQUEST;
-        else if (!lbConfig.isValid())
+        } else if (!lbConfig.isValid()) {
             return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
-        else
+        } else {
             return HttpURLConnection.HTTP_OK;
+        }
     }
 
     @Override
     public void neutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
         logger.debug("Neutron LB Pool Member Deletion : {}", neutronLBPoolMember.toString());
+        enqueueEvent(new NorthboundEvent(neutronLBPoolMember, Action.DELETE));
+    }
 
-        /* As of now, deleting a member involves recomputing member indices.
-         * This is best done through a complete update of the load balancer instance.
-         */
-        for (NeutronLoadBalancer neutronLB: neutronLBCache.getAllNeutronLoadBalancers()) {
-            String loadBalancerSubnetID = neutronLB.getLoadBalancerVipSubnetID();
-            if (neutronLBPoolMember.getPoolMemberSubnetID().equals(loadBalancerSubnetID)) {
-                enqueueEvent(new NorthboundEvent(neutronLB, Action.UPDATE));
-                break;
+    private void doNeutronLoadBalancerPoolMemberDelete(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        Preconditions.checkNotNull(loadBalancerProvider);
+
+        LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLBPoolMember);
+        final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+        if (lbConfig == null) {
+            logger.debug("Neutron LB configuration invalid for member {} ", neutronLBPoolMember.getPoolMemberAddress());
+        } else if (lbConfig.getVip() == null) {
+            logger.debug("Neutron LB VIP not created yet for member {} ", neutronLBPoolMember.getPoolMemberID());
+        } else if (!lbConfig.isValid()) {
+            logger.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+        } else if (nodes.isEmpty()) {
+            logger.debug("Noop with LB pool member {} deletion because no nodes available.", neutronLBPoolMember.getPoolMemberID());
+        } else {
+            /* As of now, deleting a member involves recomputing member indices.
+             * This is best done through a complete update of the load balancer instance.
+             */
+            LoadBalancerConfiguration newLBConfig = new LoadBalancerConfiguration(lbConfig);
+            newLBConfig.removeMember(neutronLBPoolMember.getPoolMemberID());
+
+            for (Node node : nodes) {
+                loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
+                loadBalancerProvider.programLoadBalancerRules(node, newLBConfig, Action.ADD);
             }
         }
     }
@@ -130,6 +160,7 @@ public class LBaaSPoolMemberHandler extends AbstractHandler
      */
     @Override
     public void processEvent(AbstractEvent abstractEvent) {
+        logger.debug("Processing Loadbalancer member event " + abstractEvent);
         if (!(abstractEvent instanceof NorthboundEvent)) {
             logger.error("Unable to process abstract event " + abstractEvent);
             return;
@@ -138,12 +169,14 @@ public class LBaaSPoolMemberHandler extends AbstractHandler
         switch (ev.getAction()) {
             case ADD:
                 doNeutronLoadBalancerPoolMemberCreate(ev.getLoadBalancerPoolMember());
+                break;
             case DELETE:
-                logger.warn("Load balancer pool member delete event should not have been triggered");
+                doNeutronLoadBalancerPoolMemberDelete(ev.getLoadBalancerPoolMember());
+                break;
             case UPDATE:
                 /**
                  * Typical upgrade involves changing weights. Since weights are not
-                 * supported yet, updates are not supported either.
+                 * supported yet, updates are not supported either. TODO
                  */
                 logger.warn("Load balancer pool member update is not supported");
                 break;
@@ -158,47 +191,83 @@ public class LBaaSPoolMemberHandler extends AbstractHandler
      * configuration from the neutron LB cache based on member info
      */
     public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
-        String memberIP = neutronLBPoolMember.getPoolMemberAddress();
-        String memberMAC = NeutronCacheUtils.getMacAddress(neutronPortsCache, memberIP);
-        if (memberMAC == null)
-            return null;
-
         String memberID = neutronLBPoolMember.getPoolMemberID();
+        String memberIP = neutronLBPoolMember.getPoolMemberAddress();
+        String memberSubnetID = neutronLBPoolMember.getPoolMemberSubnetID();
         Integer memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
+        String memberPoolID = neutronLBPoolMember.getPoolID();
         String memberProtocol = null;
-        boolean found = false;
-
-        for (NeutronLoadBalancerPool neutronLBPool: neutronLBPoolCache.getAllNeutronLoadBalancerPools()) {
-            List<? extends NeutronLoadBalancerPoolMember> members =
-                    (List<? extends NeutronLoadBalancerPoolMember>)neutronLBPool.getLoadBalancerPoolMembers();
-            for (NeutronLoadBalancerPoolMember member: members) {
-                //TODO: Allow member to be present in more than 1 pool
-                if (member.getPoolMemberID().equals(neutronLBPoolMember.getPoolMemberID())) {
-                    found = true;
-                    memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
-                    if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
-                            memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS)))
-                        memberProtocol = null;
-                    break;
-                }
-            }
-            if (found)
-                break;
+
+        if (memberSubnetID == null || memberID == null || memberPoolID == null) {
+            logger.debug("Neutron LB pool member details incomplete [id={}, pool_id={},subnet_id={}",
+                    memberID, memberPoolID, memberSubnetID);
+            return null;
         }
-        if (memberProtocol == null)
+        String memberMAC = NeutronCacheUtils.getMacAddress(neutronPortsCache, memberSubnetID, memberIP);
+        if (memberMAC == null) {
+            logger.debug("Neutron LB pool member {} MAC address unavailable", memberID);
             return null;
+        }
+        NeutronLoadBalancerPool neutronLBPool = neutronLBPoolCache.getNeutronLoadBalancerPool(memberPoolID);
+        memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
+        if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_TCP) ||
+                memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
+                memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
+            return null;
+        }
 
-        String loadBalancerSubnetID, loadBalancerVip, loadBalancerName;
+        String loadBalancerSubnetID=null, loadBalancerVip=null, loadBalancerName=null;
         for (NeutronLoadBalancer neutronLB: neutronLBCache.getAllNeutronLoadBalancers()) {
             loadBalancerSubnetID = neutronLB.getLoadBalancerVipSubnetID();
-            if (neutronLBPoolMember.getPoolMemberSubnetID().equals(loadBalancerSubnetID)) {
+            if (memberSubnetID.equals(loadBalancerSubnetID)) {
                 loadBalancerName = neutronLB.getLoadBalancerName();
                 loadBalancerVip = neutronLB.getLoadBalancerVipAddress();
-                LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
-                lbConfig.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
-                return lbConfig;
+                break;
+            }
+        }
+
+        /**
+         * It is possible that the VIP has not been created yet.
+         * In that case, we create dummy configuration that will not program rules.
+         */
+        LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
+        Map.Entry<String,String> providerInfo = NeutronCacheUtils.getProviderInformation(neutronNetworkCache, neutronSubnetCache, memberSubnetID);
+        if (providerInfo != null) {
+            lbConfig.setProviderNetworkType(providerInfo.getKey());
+            lbConfig.setProviderSegmentationId(providerInfo.getValue());
+        }
+        lbConfig.setVmac(NeutronCacheUtils.getMacAddress(neutronPortsCache, loadBalancerSubnetID, loadBalancerVip));
+
+        /* Extract all other active members and include in LB config
+         */
+        String otherMemberID, otherMemberSubnetID, otherMemberIP, otherMemberMAC, otherMemberProtocol;
+        Boolean otherMemberAdminStateIsUp;
+        Integer otherMemberPort;
+
+        for (NeutronLoadBalancerPoolMember otherMember: neutronLBPool.getLoadBalancerPoolMembers()) {
+            otherMemberID = otherMember.getPoolMemberID();
+            if (otherMemberID.equals(memberID)) {
+                continue; //skip
+            }
+
+            otherMemberIP = otherMember.getPoolMemberAddress();
+            otherMemberAdminStateIsUp = otherMember.getPoolMemberAdminStateIsUp();
+            otherMemberSubnetID = otherMember.getPoolMemberSubnetID();
+            otherMemberPort = otherMember.getPoolMemberProtoPort();
+            otherMemberProtocol = memberProtocol;
+
+            if (otherMemberIP == null || otherMemberSubnetID == null || otherMemberAdminStateIsUp == null) {
+                continue;
+            } else if (otherMemberAdminStateIsUp.booleanValue()) {
+                otherMemberMAC = NeutronCacheUtils.getMacAddress(neutronPortsCache, otherMemberSubnetID, otherMemberIP);
+                if (otherMemberMAC == null) {
+                    continue;
+                }
+                lbConfig.addMember(otherMemberID, otherMemberIP, otherMemberMAC, otherMemberProtocol, otherMemberPort);
             }
         }
-        return null;
+
+        lbConfig.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
+        return lbConfig;
     }
 }