Merge "Bug 4789 - allowed address pair doesn't have port id"
[ovsdb.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / LBaaSPoolMemberHandler.java
index c99ec2c0eedf19ac1e51b8a0383858629673c11a..793f7ac0916cda17a53e61df08342d1c9888a079 100755 (executable)
 /*
- * Copyright (C) 2014 SDN Hub, LLC.
+ * Copyright (c) 2014, 2015 SDN Hub, LLC. and others. 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
- *
- * 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 java.net.HttpURLConnection;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 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.ovsdb.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 
-import java.net.HttpURLConnection;
-import java.util.List;
-
 /**
  * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for
  * /v2.0/pools/{pool_id}/members
  */
 
 public class LBaaSPoolMemberHandler extends AbstractHandler
-        implements INeutronLoadBalancerPoolMemberAware {
-
-    private static final Logger logger = LoggerFactory.getLogger(LBaaSPoolMemberHandler.class);
+        implements INeutronLoadBalancerPoolMemberAware, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(LBaaSPoolMemberHandler.class);
 
     // The implementation for each of these services is resolved by the OSGi Service Manager
     private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
     private volatile INeutronLoadBalancerCRUD neutronLBCache;
-    private volatile INeutronPortCRUD neutronPortsCache;
+    private volatile INeutronPortCRUD neutronPortCache;
+    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());
+        LOG.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());
+            LOG.debug("Neutron LB configuration invalid for member {} ", neutronLBPoolMember.getPoolMemberAddress());
+        } else if (lbConfig.getVip() == null) {
+            LOG.debug("Neutron LB VIP not created yet for member {} ", neutronLBPoolMember.getID());
+        } else if (!lbConfig.isValid()) {
+            LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+        } else if (nodes.isEmpty()) {
+            LOG.debug("Noop with LB pool member {} creation because no nodes available.", neutronLBPoolMember.getID());
         } else {
-            for (Node node: this.switchManager.getNodes())
-                loadBalancerProvider.programLoadBalancerPoolMemberRules(node, lbConfig,
-                        lbConfig.getMembers().get(neutronLBPoolMember.getPoolMemberID()), Action.ADD);
+            for (Node node : nodes) {
+                loadBalancerProvider.programLoadBalancerPoolMemberRules(node,
+                        lbConfig,
+                        lbConfig.getMembers().get(neutronLBPoolMember.getID()), 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) {
+        LOG.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());
+        LOG.debug("Neutron LB Pool Member Deletion : {}", neutronLBPoolMember.toString());
         enqueueEvent(new NorthboundEvent(neutronLBPoolMember, Action.DELETE));
     }
 
     private void doNeutronLoadBalancerPoolMemberDelete(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());
+            LOG.debug("Neutron LB configuration invalid for member {} ", neutronLBPoolMember.getPoolMemberAddress());
+        } else if (lbConfig.getVip() == null) {
+            LOG.debug("Neutron LB VIP not created yet for member {} ", neutronLBPoolMember.getID());
+        } else if (!lbConfig.isValid()) {
+            LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
+        } else if (nodes.isEmpty()) {
+            LOG.debug("Noop with LB pool member {} deletion because no nodes available.", neutronLBPoolMember.getID());
         } else {
-            for (Node node: this.switchManager.getNodes())
-                loadBalancerProvider.programLoadBalancerPoolMemberRules(node, lbConfig,
-                        lbConfig.getMembers().get(neutronLBPoolMember.getPoolMemberID()), 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.
+             */
+            LoadBalancerConfiguration newLBConfig = new LoadBalancerConfiguration(lbConfig);
+            newLBConfig.removeMember(neutronLBPoolMember.getID());
+
+            for (Node node : nodes) {
+                loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
+                loadBalancerProvider.programLoadBalancerRules(node, newLBConfig, Action.ADD);
+            }
         }
     }
 
@@ -135,26 +162,28 @@ public class LBaaSPoolMemberHandler extends AbstractHandler
      */
     @Override
     public void processEvent(AbstractEvent abstractEvent) {
+        LOG.debug("Processing Loadbalancer member event {}", abstractEvent);
         if (!(abstractEvent instanceof NorthboundEvent)) {
-            logger.error("Unable to process abstract event " + abstractEvent);
+            LOG.error("Unable to process abstract event {}", abstractEvent);
             return;
         }
         NorthboundEvent ev = (NorthboundEvent) abstractEvent;
         switch (ev.getAction()) {
             case ADD:
                 doNeutronLoadBalancerPoolMemberCreate(ev.getLoadBalancerPoolMember());
+                break;
             case DELETE:
                 doNeutronLoadBalancerPoolMemberDelete(ev.getLoadBalancerPoolMember());
+                break;
             case UPDATE:
                 /**
-                 * Currently member update requires delete and re-adding
-                 * Also, weights and weight updates are not supported
+                 * Typical upgrade involves changing weights. Since weights are not
+                 * supported yet, updates are not supported either. TODO
                  */
-                doNeutronLoadBalancerPoolMemberDelete(ev.getLoadBalancerPoolMember());
-                doNeutronLoadBalancerPoolMemberCreate(ev.getLoadBalancerPoolMember());
+                LOG.warn("Load balancer pool member update is not supported");
                 break;
             default:
-                logger.warn("Unable to process event action " + ev.getAction());
+                LOG.warn("Unable to process event action {}", ev.getAction());
                 break;
         }
     }
@@ -162,49 +191,117 @@ public class LBaaSPoolMemberHandler extends AbstractHandler
     /**
      * Useful utility for extracting the loadbalancer instance
      * configuration from the neutron LB cache based on member info
+     * @param neutronLBPoolMember Neutron LB pool member object
+     * @return load balancer configuration of the pool member
      */
     public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
+        String memberID = neutronLBPoolMember.getID();
         String memberIP = neutronLBPoolMember.getPoolMemberAddress();
-        String memberMAC = NeutronCacheUtils.getMacAddress(neutronPortsCache, memberIP);
-        if (memberMAC == null)
-            return null;
-
-        String memberID = neutronLBPoolMember.getPoolMemberID();
+        String memberSubnetID = neutronLBPoolMember.getPoolMemberSubnetID();
         Integer memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
-        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;
+        String memberPoolID = neutronLBPoolMember.getPoolID();
+
+        if (memberSubnetID == null || memberID == null || memberPoolID == null) {
+            LOG.debug("Neutron LB pool member details incomplete [id={}, pool_id={},subnet_id={}",
+                    memberID, memberPoolID, memberSubnetID);
+            return null;
         }
-        if (memberProtocol == null)
+        String memberMAC = NeutronCacheUtils.getMacAddress(neutronPortCache, memberSubnetID, memberIP);
+        if (memberMAC == null) {
+            LOG.debug("Neutron LB pool member {} MAC address unavailable", memberID);
             return null;
+        }
+        NeutronLoadBalancerPool neutronLBPool = neutronLBPoolCache.getNeutronLoadBalancerPool(memberPoolID);
+        if (neutronLBPool == null) {
+            LOG.debug("Neutron LB pool {} unavailable", memberPoolID);
+            return null;
+        }
+        String 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;
             }
         }
-        return null;
+
+        /**
+         * 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(neutronPortCache, 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.getID();
+            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 &&
+                    otherMemberAdminStateIsUp) {
+                otherMemberMAC = NeutronCacheUtils.getMacAddress(neutronPortCache, otherMemberSubnetID, otherMemberIP);
+                if (otherMemberMAC == null) {
+                    continue;
+                }
+                lbConfig.addMember(otherMemberID, otherMemberIP, otherMemberMAC, otherMemberProtocol, otherMemberPort);
+            }
+        }
+
+        lbConfig.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
+        return lbConfig;
+    }
+
+    @Override
+    public void setDependencies(ServiceReference serviceReference) {
+        loadBalancerProvider =
+                (LoadBalancerProvider) ServiceHelper.getGlobalInstance(LoadBalancerProvider.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
+    }
+
+    @Override
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+        } else if (impl instanceof INeutronPortCRUD) {
+            neutronPortCache = (INeutronPortCRUD)impl;
+        } else if (impl instanceof INeutronSubnetCRUD) {
+            neutronSubnetCache = (INeutronSubnetCRUD)impl;
+        } else if (impl instanceof INeutronLoadBalancerCRUD) {
+            neutronLBCache = (INeutronLoadBalancerCRUD)impl;
+        } else if (impl instanceof INeutronLoadBalancerPoolCRUD) {
+            neutronLBPoolCache = (INeutronLoadBalancerPoolCRUD)impl;
+        } else if (impl instanceof LoadBalancerProvider) {
+            loadBalancerProvider = (LoadBalancerProvider)impl;
+        }
     }
 }