Merge "Restructing the LBaaSHandler code, and adding calls to the LoadBalancerProvide...
[ovsdb.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 org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerAware;
14 import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD;
15 import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberCRUD;
16 import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
17 import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
18 import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
19 import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
20 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
21 import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
22 import org.opendaylight.controller.sal.core.Node;
23 import org.opendaylight.controller.switchmanager.ISwitchManager;
24 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
25 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
26 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import com.google.common.base.Preconditions;
31
32 import java.net.HttpURLConnection;
33 import java.util.Iterator;
34 import java.util.List;
35
36 /**
37  * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for /v2.0/loadbalancers.
38  */
39
40 //TODO: Implement INeutronLoadBalancerHealthMonitorAware, INeutronLoadBalancerListenerAware, INeutronLoadBalancerPoolMemberAware,
41
42 public class LBaaSHandler extends AbstractHandler
43         implements INeutronLoadBalancerAware {
44
45     private static final Logger logger = LoggerFactory.getLogger(LBaaSHandler.class);
46
47     // The implementation for each of these services is resolved by the OSGi Service Manager
48     private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
49     private volatile INeutronLoadBalancerPoolMemberCRUD neutronLBPoolMemberCache;
50     private volatile INeutronPortCRUD neutronPortsCache;
51     private volatile LoadBalancerProvider loadBalancerProvider;
52     private volatile ISwitchManager switchManager;
53
54     @Override
55     public int canCreateNeutronLoadBalancer(NeutronLoadBalancer neutronLoadBalancer) {
56         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLoadBalancer);
57         if (!lbConfig.isValid())
58             return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
59         else
60             return HttpURLConnection.HTTP_OK;
61     }
62
63     /**
64      * Assuming that the pool information is fully populated before this call is made,
65      * we go with creating the LoadBalancerConfiguration object for this call with
66      * all information that is necessary to insert flow_mods
67      */
68     @Override
69     public void neutronLoadBalancerCreated(NeutronLoadBalancer neutronLoadBalancer) {
70         logger.debug("Neutron LB Creation : {}", neutronLoadBalancer.toString());
71         enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.ADD));
72     }
73
74     private void doNeutronLoadBalancerCreate(NeutronLoadBalancer neutronLoadBalancer) {
75         int result = canCreateNeutronLoadBalancer(neutronLoadBalancer);
76         if (result != HttpURLConnection.HTTP_OK) {
77             logger.debug("Neutron Load Balancer creation failed {} ", result);
78             return;
79         }
80         Preconditions.checkNotNull(loadBalancerProvider);
81         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLoadBalancer);
82
83         if (!lbConfig.isValid()) {
84             logger.trace("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
85             return;
86         } else {
87             for (Node node: this.switchManager.getNodes())
88                 loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.ADD);
89         }
90     }
91
92     @Override
93     public int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original) {
94         return HttpURLConnection.HTTP_OK;
95     }
96
97     @Override
98     public void neutronLoadBalancerUpdated(NeutronLoadBalancer neutronLoadBalancer) {
99         enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.UPDATE));
100         return;
101     }
102
103     @Override
104     public int canDeleteNeutronLoadBalancer(NeutronLoadBalancer neutronLoadBalancer) {
105         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLoadBalancer);
106         if (!lbConfig.isValid())
107             return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
108         else
109             return HttpURLConnection.HTTP_OK;
110     }
111
112     @Override
113     public void neutronLoadBalancerDeleted(NeutronLoadBalancer neutronLoadBalancer) {
114         logger.debug("Neutron LB Deletion : {}", neutronLoadBalancer.toString());
115         enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.DELETE));
116     }
117
118     private void doNeutronLoadBalancerDelete(NeutronLoadBalancer neutronLoadBalancer) {
119         int result = canDeleteNeutronLoadBalancer(neutronLoadBalancer);
120         if  (result != HttpURLConnection.HTTP_OK) {
121             logger.error(" delete Neutron NeutronLoadBalancer Pool validation failed for result - {} ", result);
122             return;
123         }
124         Preconditions.checkNotNull(loadBalancerProvider);
125         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLoadBalancer);
126
127         if (!lbConfig.isValid()) {
128             logger.trace("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
129             return;
130         } else {
131             for (Node node: this.switchManager.getNodes())
132                 loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
133         }
134     }
135
136     /**
137      * Process the event.
138      *
139      * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
140      * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
141      */
142     @Override
143     public void processEvent(AbstractEvent abstractEvent) {
144         if (!(abstractEvent instanceof NorthboundEvent)) {
145             logger.error("Unable to process abstract event " + abstractEvent);
146             return;
147         }
148         NorthboundEvent ev = (NorthboundEvent) abstractEvent;
149         switch (ev.getAction()) {
150             case ADD:
151                 doNeutronLoadBalancerCreate(ev.getLoadBalancer());
152             case DELETE:
153                 doNeutronLoadBalancerDelete(ev.getLoadBalancer());
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                 logger.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 neutronLoadBalancer) {
173         String loadBalancerName = neutronLoadBalancer.getLoadBalancerName();
174         String loadBalancerVip = neutronLoadBalancer.getLoadBalancerVipAddress();
175         String loadBalancerSubnetID = neutronLoadBalancer.getLoadBalancerVipSubnetID();
176         LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
177
178         String memberID, memberIP, memberMAC, memberProtocol;
179         Integer memberPort;
180
181         for (NeutronLoadBalancerPool neutronLBPool: neutronLBPoolCache.getAllNeutronLoadBalancerPools()) {
182             List<? extends NeutronLoadBalancerPoolMember> members =
183                 (List<? extends NeutronLoadBalancerPoolMember>)neutronLBPool.getLoadBalancerPoolMembers();
184             memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
185             /*
186              * Only HTTP and HTTPS are supported as of this version
187              * TODO: Support all TCP load-balancers
188              */
189             if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
190                   memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS)))
191                 continue;
192             for (NeutronLoadBalancerPoolMember neutronLBPoolMember: members) {
193                 if (neutronLBPoolMember.getPoolMemberSubnetID().equals(loadBalancerSubnetID)) {
194                     memberID = neutronLBPoolMember.getPoolMemberID();
195                     memberIP = neutronLBPoolMember.getPoolMemberAddress();
196                     memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
197                     memberMAC = this.getMacAddress(memberIP);
198                     if (memberMAC == null)
199                         continue;
200                     lbConfig.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
201                 }
202             }
203         }
204         return lbConfig;
205     }
206
207     /**
208      * Look up in the NeutronPortsCRUD cache and return the MAC address for a corresponding IP address
209      * @param ipAddr IP address of a member or VM
210      * @return MAC address registered with that IP address
211      */
212     public String getMacAddress(String ipAddr) {
213             List<Neutron_IPs> fixedIPs;
214             Iterator<Neutron_IPs> fixedIPIterator;
215             Neutron_IPs ip;
216
217             List<NeutronPort> allPorts = neutronPortsCache.getAllPorts();
218          Iterator<NeutronPort> i = allPorts.iterator();
219          while (i.hasNext()) {
220              NeutronPort port = i.next();
221              fixedIPs = port.getFixedIPs();
222              if (fixedIPs != null && fixedIPs.size() > 0) {
223                  fixedIPIterator = fixedIPs.iterator();
224                  while (fixedIPIterator.hasNext()) {
225                      ip = fixedIPIterator.next();
226                      if (ip.getIpAddress().equals(ipAddr))
227                          return port.getMacAddress();
228                  }
229              }
230          }
231         return null;
232     }
233 }