Merge "Clean up logging"
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / LBaaSHandler.java
1 /*
2  * Copyright (C) 2014 SDN Hub, LLC.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Authors : Srini Seetharaman
9  */
10
11 package org.opendaylight.ovsdb.openstack.netvirt;
12
13 import java.net.HttpURLConnection;
14 import java.util.List;
15 import java.util.Map;
16
17 import org.opendaylight.neutron.spi.INeutronLoadBalancerAware;
18 import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
19 import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
20 import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
21 import org.opendaylight.neutron.spi.INeutronPortCRUD;
22 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
23 import org.opendaylight.neutron.spi.NeutronLoadBalancer;
24 import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
25 import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
26 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
27 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
28 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
29 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
30 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheListener;
31 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
32 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
34 import org.osgi.framework.BundleContext;
35 import org.osgi.framework.ServiceReference;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import com.google.common.base.Preconditions;
40
41 /**
42  * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for /v2.0/loadbalancers.
43  */
44
45 //TODO: Implement INeutronLoadBalancerHealthMonitorAware, INeutronLoadBalancerListenerAware, INeutronLoadBalancerPoolMemberAware,
46
47 public class LBaaSHandler extends AbstractHandler
48         implements INeutronLoadBalancerAware, ConfigInterface, NodeCacheListener {
49     private static final Logger LOG = LoggerFactory.getLogger(LBaaSHandler.class);
50
51     // The implementation for each of these services is resolved by the OSGi Service Manager
52     private volatile INeutronLoadBalancerCRUD neutronLBCache;
53     private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
54     private volatile INeutronPortCRUD neutronPortCache;
55     private volatile INeutronNetworkCRUD neutronNetworkCache;
56     private volatile INeutronSubnetCRUD neutronSubnetCache;
57     private volatile LoadBalancerProvider loadBalancerProvider;
58     private volatile NodeCacheManager nodeCacheManager;
59
60     @Override
61     public int canCreateNeutronLoadBalancer(NeutronLoadBalancer neutronLB) {
62         //Always allowed and not wait for pool and members to be created
63         return HttpURLConnection.HTTP_OK;
64     }
65
66     @Override
67     public void neutronLoadBalancerCreated(NeutronLoadBalancer neutronLB) {
68         LOG.debug("Neutron LB Creation : {}", neutronLB.toString());
69         enqueueEvent(new NorthboundEvent(neutronLB, Action.ADD));
70     }
71
72     /**
73      * Assuming that the pool information is fully populated before this call is made,
74      * we go with creating the LoadBalancerConfiguration object for this call with
75      * all information that is necessary to insert flow_mods
76      */
77     private void doNeutronLoadBalancerCreate(NeutronLoadBalancer neutronLB) {
78         Preconditions.checkNotNull(loadBalancerProvider);
79         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
80         final List<Node> nodes = nodeCacheManager.getBridgeNodes();
81
82         if (!lbConfig.isValid()) {
83             LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
84         } else if (nodes.isEmpty()) {
85             LOG.debug("Noop with LB {} creation because no nodes available.", lbConfig.getName());
86         } else {
87             for (Node node : nodes) {
88                 loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.ADD);
89             }
90         }
91     }
92
93     @Override
94     public int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original) {
95         //Update allowed anytime, even when the LB has no active pool yet
96         return HttpURLConnection.HTTP_OK;
97     }
98
99     @Override
100     public void neutronLoadBalancerUpdated(NeutronLoadBalancer neutronLB) {
101         LOG.debug("Neutron LB Update : {}", neutronLB.toString());
102         enqueueEvent(new NorthboundEvent(neutronLB, Action.UPDATE));
103     }
104
105     @Override
106     public int canDeleteNeutronLoadBalancer(NeutronLoadBalancer neutronLB) {
107         //Always allowed and not wait for pool to stop using it
108         return HttpURLConnection.HTTP_OK;
109     }
110
111     @Override
112     public void neutronLoadBalancerDeleted(NeutronLoadBalancer neutronLB) {
113         LOG.debug("Neutron LB Deletion : {}", neutronLB.toString());
114         enqueueEvent(new NorthboundEvent(neutronLB, Action.DELETE));
115     }
116
117     private void doNeutronLoadBalancerDelete(NeutronLoadBalancer neutronLB) {
118         Preconditions.checkNotNull(loadBalancerProvider);
119         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
120         final List<Node> nodes = nodeCacheManager.getBridgeNodes();
121
122         if (!lbConfig.isValid()) {
123             LOG.debug("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
124         } else if (nodes.isEmpty()) {
125             LOG.debug("Noop with LB {} deletion because no nodes available.", lbConfig.getName());
126         } else {
127             for (Node node : nodes) {
128                 loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
129             }
130         }
131     }
132
133     /**
134      * Process the event.
135      *
136      * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
137      * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
138      */
139     @Override
140     public void processEvent(AbstractEvent abstractEvent) {
141         LOG.debug("Processing Loadbalancer event {}", abstractEvent);
142         if (!(abstractEvent instanceof NorthboundEvent)) {
143             LOG.error("Unable to process abstract event {}", abstractEvent);
144             return;
145         }
146         NorthboundEvent ev = (NorthboundEvent) abstractEvent;
147         switch (ev.getAction()) {
148             case ADD:
149                 doNeutronLoadBalancerCreate(ev.getLoadBalancer());
150                 break;
151             case DELETE:
152                 doNeutronLoadBalancerDelete(ev.getLoadBalancer());
153                 break;
154             case UPDATE:
155                 /**
156                  * Currently member update requires delete and re-adding
157                  * Also, weights and weight updates are not supported
158                  */
159                 doNeutronLoadBalancerDelete(ev.getLoadBalancer());
160                 doNeutronLoadBalancerCreate(ev.getLoadBalancer());
161                 break;
162             default:
163                 LOG.warn("Unable to process event action {}", ev.getAction());
164                 break;
165         }
166     }
167
168     /**
169      * Useful utility for extracting the loadbalancer instance
170      * configuration from the neutron LB cache
171      */
172     public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancer neutronLB) {
173         String loadBalancerName = neutronLB.getLoadBalancerName();
174         String loadBalancerVip = neutronLB.getLoadBalancerVipAddress();
175         String loadBalancerSubnetID = neutronLB.getLoadBalancerVipSubnetID();
176
177         LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
178         Map.Entry<String,String> providerInfo =
179                 NeutronCacheUtils.getProviderInformation(neutronNetworkCache, neutronSubnetCache, loadBalancerSubnetID);
180         if (providerInfo != null) {
181             lbConfig.setProviderNetworkType(providerInfo.getKey());
182             lbConfig.setProviderSegmentationId(providerInfo.getValue());
183         }
184         lbConfig.setVmac(NeutronCacheUtils.getMacAddress(neutronPortCache, loadBalancerSubnetID, loadBalancerVip));
185
186         String memberID, memberIP, memberMAC, memberProtocol, memberSubnetID;
187         Integer memberPort;
188         Boolean memberAdminStateIsUp;
189
190         for (NeutronLoadBalancerPool neutronLBPool: neutronLBPoolCache.getAllNeutronLoadBalancerPools()) {
191             List<NeutronLoadBalancerPoolMember> members = neutronLBPool.getLoadBalancerPoolMembers();
192             memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
193             if (memberProtocol == null) {
194                 continue;
195             }
196
197             if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_TCP) ||
198                   memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
199                   memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))) {
200                 continue;
201             }
202             for (NeutronLoadBalancerPoolMember neutronLBPoolMember: members) {
203                 memberAdminStateIsUp = neutronLBPoolMember.getPoolMemberAdminStateIsUp();
204                 memberSubnetID = neutronLBPoolMember.getPoolMemberSubnetID();
205                 if (memberSubnetID == null || memberAdminStateIsUp == null) {
206                     continue;
207                 }
208                 else if (memberSubnetID.equals(loadBalancerSubnetID) && memberAdminStateIsUp.booleanValue()) {
209                     memberID = neutronLBPoolMember.getPoolMemberID();
210                     memberIP = neutronLBPoolMember.getPoolMemberAddress();
211                     memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
212                     if (memberSubnetID == null || memberID == null || memberIP == null || memberPort == null) {
213                         LOG.debug("Neutron LB pool member details incomplete: {}", neutronLBPoolMember);
214                         continue;
215                     }
216                     memberMAC = NeutronCacheUtils.getMacAddress(neutronPortCache, memberSubnetID, memberIP);
217                     if (memberMAC == null) {
218                         continue;
219                     }
220                     lbConfig.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
221                 }
222             }
223         }
224         return lbConfig;
225     }
226
227     /**
228      * On the addition of a new node, we iterate through all existing loadbalancer
229      * instances and program the node for all of them. It is sufficient to do that only
230      * when a node is added, and only for the LB instances (and not individual members).
231      */
232     @Override
233     public void notifyNode(Node node, Action type) {
234         LOG.debug("notifyNode: Node {} update {} from Controller's inventory Service", node, type);
235         Preconditions.checkNotNull(loadBalancerProvider);
236
237         for (NeutronLoadBalancer neutronLB: neutronLBCache.getAllNeutronLoadBalancers()) {
238             LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
239             if (!lbConfig.isValid()) {
240                 LOG.debug("Neutron LB configuration invalid for {} ", lbConfig.getName());
241             } else {
242                if (type.equals(Action.ADD)) {
243                    loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.ADD);
244
245                /* When node disappears, we do nothing for now. Making a call to
246                 * loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE)
247                 * can lead to TransactionCommitFailedException. Similarly when node is changed,
248                 * because of remove followed by add, we do nothing.
249                 */
250
251                  //(type.equals(UpdateType.REMOVED) || type.equals(UpdateType.CHANGED))
252                } else {
253                    continue;
254                }
255             }
256         }
257     }
258
259     @Override
260     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
261         loadBalancerProvider =
262                 (LoadBalancerProvider) ServiceHelper.getGlobalInstance(LoadBalancerProvider.class, this);
263         nodeCacheManager =
264                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
265         nodeCacheManager.cacheListenerAdded(
266                 bundleContext.getServiceReference(INeutronLoadBalancerAware.class.getName()), this);
267         eventDispatcher =
268                 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
269         eventDispatcher.eventHandlerAdded(
270                 bundleContext.getServiceReference(INeutronLoadBalancerAware.class.getName()), this);
271     }
272
273     @Override
274     public void setDependencies(Object impl) {
275         if (impl instanceof INeutronNetworkCRUD) {
276             neutronNetworkCache = (INeutronNetworkCRUD)impl;
277         } else if (impl instanceof INeutronPortCRUD) {
278             neutronPortCache = (INeutronPortCRUD)impl;
279         } else if (impl instanceof INeutronSubnetCRUD) {
280             neutronSubnetCache = (INeutronSubnetCRUD)impl;
281         } else if (impl instanceof INeutronLoadBalancerCRUD) {
282             neutronLBCache = (INeutronLoadBalancerCRUD)impl;
283         } else if (impl instanceof INeutronLoadBalancerPoolCRUD) {
284             neutronLBPoolCache = (INeutronLoadBalancerPoolCRUD)impl;
285         } else if (impl instanceof LoadBalancerProvider) {
286             loadBalancerProvider = (LoadBalancerProvider)impl;
287         }
288     }
289 }