Merge "Net-Virt LBaaS module updates for neutron event handling"
[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.sal.core.Node;
21 import org.opendaylight.controller.switchmanager.ISwitchManager;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
23 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
24 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 import com.google.common.base.Preconditions;
29
30 import java.net.HttpURLConnection;
31 import java.util.List;
32
33 /**
34  * Handle requests for OpenStack Neutron v2.0 LBaaS API calls for /v2.0/loadbalancers.
35  */
36
37 //TODO: Implement INeutronLoadBalancerHealthMonitorAware, INeutronLoadBalancerListenerAware, INeutronLoadBalancerPoolMemberAware,
38
39 public class LBaaSHandler extends AbstractHandler
40         implements INeutronLoadBalancerAware {
41
42     private static final Logger logger = LoggerFactory.getLogger(LBaaSHandler.class);
43
44     // The implementation for each of these services is resolved by the OSGi Service Manager
45     private volatile INeutronLoadBalancerPoolCRUD neutronLBPoolCache;
46     private volatile INeutronLoadBalancerPoolMemberCRUD neutronLBPoolMemberCache;
47     private volatile INeutronPortCRUD neutronPortsCache;
48     private volatile LoadBalancerProvider loadBalancerProvider;
49     private volatile ISwitchManager switchManager;
50
51     @Override
52     public int canCreateNeutronLoadBalancer(NeutronLoadBalancer neutronLB) {
53         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
54         if (!lbConfig.isValid())
55             return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
56         else
57             return HttpURLConnection.HTTP_OK;
58     }
59
60     /**
61      * Assuming that the pool information is fully populated before this call is made,
62      * we go with creating the LoadBalancerConfiguration object for this call with
63      * all information that is necessary to insert flow_mods
64      */
65     @Override
66     public void neutronLoadBalancerCreated(NeutronLoadBalancer neutronLB) {
67         logger.debug("Neutron LB Creation : {}", neutronLB.toString());
68         enqueueEvent(new NorthboundEvent(neutronLB, Action.ADD));
69     }
70
71     private void doNeutronLoadBalancerCreate(NeutronLoadBalancer neutronLB) {
72         Preconditions.checkNotNull(loadBalancerProvider);
73         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
74
75         if (!lbConfig.isValid()) {
76             logger.trace("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
77         } else {
78             for (Node node: this.switchManager.getNodes())
79                 loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.ADD);
80         }
81     }
82
83     @Override
84     public int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original) {
85         return HttpURLConnection.HTTP_OK;
86     }
87
88     @Override
89     public void neutronLoadBalancerUpdated(NeutronLoadBalancer neutronLB) {
90         enqueueEvent(new NorthboundEvent(neutronLB, Action.UPDATE));
91         return;
92     }
93
94     @Override
95     public int canDeleteNeutronLoadBalancer(NeutronLoadBalancer neutronLB) {
96         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
97         if (!lbConfig.isValid())
98             return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
99         else
100             return HttpURLConnection.HTTP_OK;
101     }
102
103     @Override
104     public void neutronLoadBalancerDeleted(NeutronLoadBalancer neutronLB) {
105         logger.debug("Neutron LB Deletion : {}", neutronLB.toString());
106         enqueueEvent(new NorthboundEvent(neutronLB, Action.DELETE));
107     }
108
109     private void doNeutronLoadBalancerDelete(NeutronLoadBalancer neutronLB) {
110         Preconditions.checkNotNull(loadBalancerProvider);
111         LoadBalancerConfiguration lbConfig = extractLBConfiguration(neutronLB);
112
113         if (!lbConfig.isValid()) {
114             logger.trace("Neutron LB pool configuration invalid for {} ", lbConfig.getName());
115         } else {
116             for (Node node: this.switchManager.getNodes())
117                 loadBalancerProvider.programLoadBalancerRules(node, lbConfig, Action.DELETE);
118         }
119     }
120
121     /**
122      * Process the event.
123      *
124      * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
125      * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
126      */
127     @Override
128     public void processEvent(AbstractEvent abstractEvent) {
129         if (!(abstractEvent instanceof NorthboundEvent)) {
130             logger.error("Unable to process abstract event " + abstractEvent);
131             return;
132         }
133         NorthboundEvent ev = (NorthboundEvent) abstractEvent;
134         switch (ev.getAction()) {
135             case ADD:
136                 doNeutronLoadBalancerCreate(ev.getLoadBalancer());
137             case DELETE:
138                 doNeutronLoadBalancerDelete(ev.getLoadBalancer());
139             case UPDATE:
140                 /**
141                  * Currently member update requires delete and re-adding
142                  * Also, weights and weight updates are not supported
143                  */
144                 doNeutronLoadBalancerDelete(ev.getLoadBalancer());
145                 doNeutronLoadBalancerCreate(ev.getLoadBalancer());
146                 break;
147             default:
148                 logger.warn("Unable to process event action " + ev.getAction());
149                 break;
150         }
151     }
152
153     /**
154      * Useful utility for extracting the loadbalancer instance
155      * configuration from the neutron LB cache
156      */
157     public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancer neutronLB) {
158         String loadBalancerName = neutronLB.getLoadBalancerName();
159         String loadBalancerVip = neutronLB.getLoadBalancerVipAddress();
160         String loadBalancerSubnetID = neutronLB.getLoadBalancerVipSubnetID();
161         LoadBalancerConfiguration lbConfig = new LoadBalancerConfiguration(loadBalancerName, loadBalancerVip);
162
163         String memberID, memberIP, memberMAC, memberProtocol;
164         Integer memberPort;
165
166         for (NeutronLoadBalancerPool neutronLBPool: neutronLBPoolCache.getAllNeutronLoadBalancerPools()) {
167             List<? extends NeutronLoadBalancerPoolMember> members =
168                 (List<? extends NeutronLoadBalancerPoolMember>)neutronLBPool.getLoadBalancerPoolMembers();
169             memberProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
170             /*
171              * Only HTTP and HTTPS are supported as of this version
172              * TODO: Support all TCP load-balancers
173              */
174             if (!(memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP) ||
175                   memberProtocol.equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS)))
176                 continue;
177             for (NeutronLoadBalancerPoolMember neutronLBPoolMember: members) {
178                 if (neutronLBPoolMember.getPoolMemberSubnetID().equals(loadBalancerSubnetID) &&
179                     neutronLBPoolMember.getPoolMemberAdminStateIsUp()) {
180                     memberID = neutronLBPoolMember.getPoolMemberID();
181                     memberIP = neutronLBPoolMember.getPoolMemberAddress();
182                     memberPort = neutronLBPoolMember.getPoolMemberProtoPort();
183                     memberMAC = NeutronCacheUtils.getMacAddress(neutronPortsCache, memberIP);
184                     if (memberMAC == null)
185                         continue;
186                     lbConfig.addMember(memberID, memberIP, memberMAC, memberProtocol, memberPort);
187                 }
188             }
189         }
190         return lbConfig;
191     }
192 }