Merge "Making changes to LBaaSHandler and Activator to add logic for LB Neutron calls."
[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.ovsdb.openstack.netvirt.api.Action;
23 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import com.google.common.collect.Maps;
28
29 import java.net.HttpURLConnection;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33
34 /**
35  * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for /v2.0/loadbalancers.
36  */
37
38 //TODO: Implement INeutronLoadBalancerHealthMonitorAware, INeutronLoadBalancerListenerAware, INeutronLoadBalancerPoolMemberAware,
39
40 public class LBaaSHandler extends AbstractHandler
41         implements INeutronLoadBalancerAware {
42
43     private static final Logger logger = LoggerFactory.getLogger(LBaaSHandler.class);
44
45     // The implementation for each of these services is resolved by the OSGi Service Manager
46     private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
47     private volatile INeutronLoadBalancerPoolMemberCRUD neutronLBPoolMemberCache;
48     private volatile INeutronPortCRUD neutronPortsCache;
49     private Map<String, LoadBalancerConfiguration> loadbalancersCache = Maps.newHashMap();
50
51     @Override
52     public int canCreateNeutronLoadBalancer(NeutronLoadBalancer neutronLoadBalancer) {
53         if (loadbalancersCache.containsKey(neutronLoadBalancer.getLoadBalancerID()))
54             return HttpURLConnection.HTTP_CONFLICT;
55         return HttpURLConnection.HTTP_OK;
56     }
57
58     /**
59      * Assuming that the pool information is fully populated before this call is made,
60      * we go with creating the LoadBalancerConfiguration object for this call with
61      * all information that is necessary to insert flow_mods
62      */
63     @Override
64     public void neutronLoadBalancerCreated(NeutronLoadBalancer neutronLoadBalancer) {
65         logger.debug("Neutron LB Creation : {}", neutronLoadBalancer.toString());
66         enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.ADD));
67     }
68
69     private void doNeutronLoadBalancerCreate(NeutronLoadBalancer neutronLoadBalancer) {
70         int result = canCreateNeutronLoadBalancer(neutronLoadBalancer);
71         if (result != HttpURLConnection.HTTP_OK) {
72             logger.debug("Neutron Load Balancer creation failed {} ", result);
73             return;
74         }
75
76         String loadBalancerID = neutronLoadBalancer.getLoadBalancerID();
77         String loadBalancerName = neutronLoadBalancer.getLoadBalancerName();
78         String loadBalancerVip = neutronLoadBalancer.getLoadBalancerVipAddress();
79         String loadBalancerSubnetID = neutronLoadBalancer.getLoadBalancerVipSubnetID();
80         LoadBalancerConfiguration newLB = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
81
82         String memberID, memberIP, memberMAC, memberProtocol;
83         Integer memberPort;
84
85         for (NeutronLoadBalancerPool neutronLBPool: neutronLBPoolCache.getAllNeutronLoadBalancerPools()) {
86             List<? extends NeutronLoadBalancerPoolMember> members =
87                 (List<? extends NeutronLoadBalancerPoolMember>)neutronLBPool.getLoadBalancerPoolMembers();
88             memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
89             /*
90              * Only HTTP and HTTPS are supported as of this version
91              * TODO: Support all TCP load-balancers
92              */
93             if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
94                   memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS)))
95                 continue;
96             for (NeutronLoadBalancerPoolMember neutronLBPoolMember: members) {
97                 if (neutronLBPoolMember.getPoolMemberSubnetID().equals(loadBalancerSubnetID)) {
98                     memberID = neutronLBPoolMember.getPoolMemberID();
99                     memberIP = neutronLBPoolMember.getPoolMemberAddress();
100                     memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
101                     memberMAC = this.getMacAddress(memberIP);
102                     if (memberMAC == null)
103                         continue;
104                     newLB.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
105                 }
106             }
107         }
108         if (newLB.isValid()) {
109             logger.trace("Neutron LB pool configuration invalid for {} ", loadBalancerName);
110             return;
111         } else {
112             loadbalancersCache.put(loadBalancerID, newLB);
113             //TODO: Trigger flowmod addition
114         }
115     }
116
117     @Override
118     public int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original) {
119         return HttpURLConnection.HTTP_OK;
120     }
121
122     @Override
123     public void neutronLoadBalancerUpdated(NeutronLoadBalancer neutronLoadBalancer) {
124         enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.UPDATE));
125         return;
126     }
127
128     @Override
129     public int canDeleteNeutronLoadBalancer(NeutronLoadBalancer neutronLoadBalancer) {
130         if (!loadbalancersCache.containsKey(neutronLoadBalancer.getLoadBalancerID()))
131             return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
132         return HttpURLConnection.HTTP_OK;
133     }
134
135     @Override
136     public void neutronLoadBalancerDeleted(NeutronLoadBalancer neutronLoadBalancer) {
137         logger.debug("Neutron LB Deletion : {}", neutronLoadBalancer.toString());
138         enqueueEvent(new NorthboundEvent(neutronLoadBalancer, Action.DELETE));
139     }
140
141     private void doNeutronLoadBalancerDelete(NeutronLoadBalancer neutronLoadBalancer) {
142         int result = canDeleteNeutronLoadBalancer(neutronLoadBalancer);
143         if  (result != HttpURLConnection.HTTP_OK) {
144             logger.error(" delete Neutron NeutronLoadBalancer Pool validation failed for result - {} ", result);
145             return;
146         }
147         loadbalancersCache.remove(neutronLoadBalancer.getLoadBalancerID());
148         //TODO: Trigger flowmod removals
149     }
150
151     /**
152      * Process the event.
153      *
154      * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
155      * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
156      */
157     @Override
158     public void processEvent(AbstractEvent abstractEvent) {
159         if (!(abstractEvent instanceof NorthboundEvent)) {
160             logger.error("Unable to process abstract event " + abstractEvent);
161             return;
162         }
163         NorthboundEvent ev = (NorthboundEvent) abstractEvent;
164         switch (ev.getAction()) {
165             case ADD:
166                 doNeutronLoadBalancerCreate(ev.getLoadBalancer());
167             case DELETE:
168                 doNeutronLoadBalancerDelete(ev.getLoadBalancer());
169                 // fall through
170             case UPDATE:
171                 doNeutronLoadBalancerDelete(ev.getLoadBalancer());
172                 doNeutronLoadBalancerCreate(ev.getLoadBalancer());
173                 break;
174             default:
175                 logger.warn("Unable to process event action " + ev.getAction());
176                 break;
177         }
178     }
179
180     /**
181      * Look up in the NeutronPortsCRUD cache and return the MAC address for a corresponding IP address
182      * @param ipAddr IP address of a member or VM
183      * @return MAC address registered with that IP address
184      */
185     private String getMacAddress(String ipAddr) {
186             List<Neutron_IPs> fixedIPs;
187             Iterator<Neutron_IPs> fixedIPIterator;
188             Neutron_IPs ip;
189
190             List<NeutronPort> allPorts = neutronPortsCache.getAllPorts();
191          Iterator<NeutronPort> i = allPorts.iterator();
192          while (i.hasNext()) {
193              NeutronPort port = i.next();
194              fixedIPs = port.getFixedIPs();
195              if (fixedIPs != null && fixedIPs.size() > 0) {
196                  fixedIPIterator = fixedIPs.iterator();
197                  while (fixedIPIterator.hasNext()) {
198                      ip = fixedIPIterator.next();
199                      if (ip.getIpAddress().equals(ipAddr))
200                          return port.getMacAddress();
201                  }
202              }
203          }
204         return null;
205     }
206 }