blob: c9ed160183b8ab732f6eec0bf542fbc8b80661aa [file] [log] [blame]
Jonathan Hartd82f20d2013-02-21 18:04:24 -08001package net.onrc.onos.registry.controller;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08002
Jonathan Hartbd181b62013-02-17 16:05:38 -08003import java.io.IOException;
Jonathan Hartedd6a442013-02-20 15:22:06 -08004import java.io.UnsupportedEncodingException;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08005import java.util.ArrayList;
6import java.util.Collection;
Jonathan Hart3d7730a2013-02-22 11:51:17 -08007import java.util.Collections;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08008import java.util.HashMap;
Jonathan Hartedd6a442013-02-20 15:22:06 -08009import java.util.List;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080010import java.util.Map;
11
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080012import net.floodlightcontroller.core.module.FloodlightModuleContext;
13import net.floodlightcontroller.core.module.FloodlightModuleException;
14import net.floodlightcontroller.core.module.IFloodlightModule;
15import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080016import net.floodlightcontroller.restserver.IRestApiService;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080017
Jonathan Hartedd6a442013-02-20 15:22:06 -080018import org.apache.zookeeper.CreateMode;
Jonathan Hartbd181b62013-02-17 16:05:38 -080019import org.apache.zookeeper.WatchedEvent;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080020import org.apache.zookeeper.Watcher.Event.KeeperState;
Jonathan Hartbd181b62013-02-17 16:05:38 -080021import org.openflow.util.HexString;
22import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080024
Jonathan Hartd10008d2013-02-23 17:04:08 -080025import com.google.common.base.Charsets;
Jonathan Hartbd181b62013-02-17 16:05:38 -080026import com.netflix.curator.RetryPolicy;
27import com.netflix.curator.framework.CuratorFramework;
28import com.netflix.curator.framework.CuratorFrameworkFactory;
29import com.netflix.curator.framework.api.CuratorWatcher;
Jonathan Hartedd6a442013-02-20 15:22:06 -080030import com.netflix.curator.framework.recipes.cache.ChildData;
31import com.netflix.curator.framework.recipes.cache.PathChildrenCache;
32import com.netflix.curator.framework.recipes.cache.PathChildrenCache.StartMode;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080033import com.netflix.curator.framework.recipes.cache.PathChildrenCacheEvent;
34import com.netflix.curator.framework.recipes.cache.PathChildrenCacheListener;
Jonathan Hartbd181b62013-02-17 16:05:38 -080035import com.netflix.curator.framework.recipes.leader.LeaderLatch;
Jonathan Hart0de09492013-03-13 14:37:21 -070036import com.netflix.curator.framework.recipes.leader.LeaderLatchEvent;
37import com.netflix.curator.framework.recipes.leader.LeaderLatchListener;
Jonathan Hartbd181b62013-02-17 16:05:38 -080038import com.netflix.curator.framework.recipes.leader.Participant;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080039import com.netflix.curator.retry.ExponentialBackoffRetry;
Jonathan Hartbd181b62013-02-17 16:05:38 -080040
Jonathan Hart7bf62172013-02-28 13:17:18 -080041/**
42 * A registry service that uses Zookeeper. All data is stored in Zookeeper,
43 * so this can be used as a global registry in a multi-node ONOS cluster.
44 * @author jono
45 *
46 */
Jonathan Hartbd766972013-02-22 15:13:03 -080047public class ZookeeperRegistry implements IFloodlightModule, IControllerRegistryService {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080048
Jonathan Hartbd766972013-02-22 15:13:03 -080049 protected static Logger log = LoggerFactory.getLogger(ZookeeperRegistry.class);
50 protected String controllerId = null;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080051
Jonathan Hart3d7730a2013-02-22 11:51:17 -080052 protected IRestApiService restApi;
53
Jonathan Hart7bf62172013-02-28 13:17:18 -080054 //This is the default, it's overwritten by the connectionString configuration parameter
Jonathan Hartbd181b62013-02-17 16:05:38 -080055 protected String connectionString = "localhost:2181";
Jonathan Hart3d7730a2013-02-22 11:51:17 -080056
Jonathan Hartbd181b62013-02-17 16:05:38 -080057 private final String namespace = "onos";
Jonathan Hartedd6a442013-02-20 15:22:06 -080058 private final String switchLatchesPath = "/switches";
Jonathan Hart3d7730a2013-02-22 11:51:17 -080059 private final String controllerPath = "/controllers";
Jonathan Hartbd181b62013-02-17 16:05:38 -080060
61 protected CuratorFramework client;
Jonathan Hartedd6a442013-02-20 15:22:06 -080062
Jonathan Hartedd6a442013-02-20 15:22:06 -080063 protected PathChildrenCache controllerCache;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080064 protected PathChildrenCache switchCache;
Jonathan Hartbd181b62013-02-17 16:05:38 -080065
66 protected Map<String, LeaderLatch> switchLatches;
Jonathan Hartd82f20d2013-02-21 18:04:24 -080067 protected Map<String, ControlChangeCallback> switchCallbacks;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080068 protected Map<String, PathChildrenCache> switchPathCaches;
Jonathan Hartbd181b62013-02-17 16:05:38 -080069
Jonathan Hart97801ac2013-02-26 14:29:16 -080070 //Zookeeper performance-related configuration
Jonathan Hartcc957a02013-02-26 10:39:04 -080071 protected static final int sessionTimeout = 2000;
72 protected static final int connectionTimeout = 4000;
Jonathan Hart57080fb2013-02-21 10:55:46 -080073
Jonathan Hart7bf62172013-02-28 13:17:18 -080074 /**
75 * Watches for changes in switch leadership election. The Curator
76 * LeaderLatch doesn't notify us when leadership changes so we set a watch
77 * on the election znodes to get leadership change events. The process
78 * method will be called whenever the switches children change in
79 * Zookeeper. We then have to work out whether to send a control-changed
80 * event to our clients and reset the watch.
81 *
82 * TODO I think it's possible to miss events that happen while we're
83 * processing the watch and before we've set a new watch. Need to think
84 * of a safer way to implement leader change notifications.
85 *
86 */
Jonathan Hartbd181b62013-02-17 16:05:38 -080087 protected class ParamaterizedCuratorWatcher implements CuratorWatcher {
88 private String dpid;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080089 private boolean isLeader = false;
Jonathan Hartbd181b62013-02-17 16:05:38 -080090 private String latchPath;
91
92 public ParamaterizedCuratorWatcher(String dpid, String latchPath){
93 this.dpid = dpid;
94 this.latchPath = latchPath;
95 }
96
97 @Override
Jonathan Hartedd6a442013-02-20 15:22:06 -080098 public synchronized void process(WatchedEvent event) throws Exception {
Jonathan Hartbd181b62013-02-17 16:05:38 -080099 log.debug("Watch Event: {}", event);
100
Jonathan Hartbd181b62013-02-17 16:05:38 -0800101
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800102 if (event.getState() == KeeperState.Disconnected){
103 if (isLeader) {
104 log.debug("Disconnected while leader - lost leadership for {}", dpid);
105
106 isLeader = false;
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800107 ControlChangeCallback cb = switchCallbacks.get(dpid);
108 if (cb != null) {
109 //Allow callback to be null if the requester doesn't want a callback
110 cb.controlChanged(HexString.toLong(dpid), false);
111 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800112 }
113 return;
Jonathan Hart7bf62172013-02-28 13:17:18 -0800114 //TODO Watcher is never reset once we reconnect to Zookeeper
115 }
116
117 LeaderLatch latch = switchLatches.get(dpid);
118 if (latch == null){
119 log.debug("In watcher process, looks like control was released for {}",
120 dpid);
121 return;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800122 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800123
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800124 try {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800125
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800126 Participant leader = latch.getLeader();
127
Jonathan Hartbd766972013-02-22 15:13:03 -0800128 if (leader.getId().equals(controllerId) && !isLeader){
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800129 log.debug("Became leader for {}", dpid);
130
131 isLeader = true;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800132 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), true);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800133 }
Jonathan Hartbd766972013-02-22 15:13:03 -0800134 else if (!leader.getId().equals(controllerId) && isLeader){
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800135 log.debug("Lost leadership for {}", dpid);
136
137 isLeader = false;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800138 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), false);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800139 }
140 } catch (Exception e){
141 if (isLeader){
Jonathan Hart7bf62172013-02-28 13:17:18 -0800142 log.debug("Exception checking leadership status. Assume leadership lost for {}",
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800143 dpid);
144
145 isLeader = false;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800146 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), false);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800147 }
Jonathan Hart7bf62172013-02-28 13:17:18 -0800148 } finally {
149 client.getChildren().usingWatcher(this).inBackground().forPath(latchPath);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800150 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800151 //client.getChildren().usingWatcher(this).forPath(latchPath);
152 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800153 }
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800154
Jonathan Hart0de09492013-03-13 14:37:21 -0700155 protected class ParamaterizedLeaderListener implements LeaderLatchListener{
156 String dpid;
157 LeaderLatch latch;
158
159 public ParamaterizedLeaderListener(String dpid, LeaderLatch latch){
160 this.dpid = dpid;
161 this.latch = latch;
162 }
163
164 @Override
165 public void leaderLatchEvent(CuratorFramework arg0,
166 LeaderLatchEvent arg1) {
167 log.debug("Got leader latch event for {} hasLeadership {}",
168 dpid, latch.hasLeadership());
169
170 }
171 }
172
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800173
Jonathan Hart7bf62172013-02-28 13:17:18 -0800174 /**
175 * Listens for changes to the switch znodes in Zookeeper. This maintains
176 * the second level of PathChildrenCaches that hold the controllers
177 * contending for each switch - there's one for each switch.
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800178 */
179 PathChildrenCacheListener switchPathCacheListener = new PathChildrenCacheListener() {
180 @Override
181 public void childEvent(CuratorFramework client,
182 PathChildrenCacheEvent event) throws Exception {
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800183 log.debug("Root switch path cache got {} event", event.getType());
184
185 String strSwitch = null;
186 if (event.getData() != null){
187 log.debug("Event path {}", event.getData().getPath());
188 String[] splitted = event.getData().getPath().split("/");
189 strSwitch = splitted[splitted.length - 1];
190 log.debug("Switch name is {}", strSwitch);
191 }
192
193 switch (event.getType()){
194 case CHILD_ADDED:
195 case CHILD_UPDATED:
196 //Check we have a PathChildrenCache for this child, add one if not
197 if (switchPathCaches.get(strSwitch) == null){
198 PathChildrenCache pc = new PathChildrenCache(client,
199 event.getData().getPath(), true);
200 pc.start(StartMode.NORMAL);
201 switchPathCaches.put(strSwitch, pc);
202 }
203 break;
204 case CHILD_REMOVED:
205 //Remove our PathChildrenCache for this child
206 PathChildrenCache pc = switchPathCaches.remove(strSwitch);
207 pc.close();
208 break;
209 default:
210 //All other events are connection status events. We need to do anything
211 //as the path cache handles these on its own.
212 break;
213 }
214
215 }
216 };
Jonathan Hartedd6a442013-02-20 15:22:06 -0800217
Jonathan Hartbd181b62013-02-17 16:05:38 -0800218
219 @Override
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800220 public void requestControl(long dpid, ControlChangeCallback cb) throws RegistryException {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800221 log.info("Requesting control for {}", HexString.toHexString(dpid));
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800222
Jonathan Hartbd766972013-02-22 15:13:03 -0800223 if (controllerId == null){
224 throw new RuntimeException("Must register a controller before calling requestControl");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800225 }
226
227 String dpidStr = HexString.toHexString(dpid);
228 String latchPath = switchLatchesPath + "/" + dpidStr;
229
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800230 if (switchLatches.get(dpidStr) != null){
Jonathan Hart3c0eccd2013-03-12 22:32:50 -0700231 //throw new RuntimeException("Leader election for switch " + dpidStr +
232 // "is already running");
233 log.debug("Already contesting {}, returning", HexString.toHexString(dpid));
234 return;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800235 }
236
Jonathan Hartbd766972013-02-22 15:13:03 -0800237 LeaderLatch latch = new LeaderLatch(client, latchPath, controllerId);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800238 switchLatches.put(dpidStr, latch);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800239 switchCallbacks.put(dpidStr, cb);
240
Jonathan Hart0de09492013-03-13 14:37:21 -0700241 latch.addListener(new ParamaterizedLeaderListener(dpidStr, latch));
242
Jonathan Hartbd181b62013-02-17 16:05:38 -0800243 try {
244 //client.getChildren().usingWatcher(watcher).inBackground().forPath(singleLatchPath);
Jonathan Hart0de09492013-03-13 14:37:21 -0700245 //client.getChildren().usingWatcher(
246 // new ParamaterizedCuratorWatcher(dpidStr, latchPath))
247 // .inBackground().forPath(latchPath);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800248 latch.start();
249 } catch (Exception e) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800250 log.warn("Error starting leader latch: {}", e.getMessage());
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800251 throw new RegistryException("Error starting leader latch for " + dpidStr, e);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800252 }
253
254 }
255
256 @Override
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800257 public void releaseControl(long dpid) {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800258 log.info("Releasing control for {}", HexString.toHexString(dpid));
Jonathan Hart57080fb2013-02-21 10:55:46 -0800259
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800260 String dpidStr = HexString.toHexString(dpid);
261
262 LeaderLatch latch = switchLatches.get(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800263 if (latch == null) {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800264 log.debug("Trying to release control of a switch we are not contesting");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800265 return;
266 }
267
268 try {
269 latch.close();
270 } catch (IOException e) {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800271 //I think it's OK not to do anything here. Either the node got
272 //deleted correctly, or the connection went down and the node got deleted.
Jonathan Hart1be46262013-02-20 16:43:51 -0800273 } finally {
274 switchLatches.remove(dpidStr);
275 switchCallbacks.remove(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800276 }
277 }
278
279 @Override
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800280 public boolean hasControl(long dpid) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800281
Jonathan Hartbd181b62013-02-17 16:05:38 -0800282 LeaderLatch latch = switchLatches.get(HexString.toHexString(dpid));
283
284 if (latch == null) {
285 log.warn("No leader latch for dpid {}", HexString.toHexString(dpid));
286 return false;
287 }
288
Jonathan Hartbd181b62013-02-17 16:05:38 -0800289 try {
Jonathan Hartbd766972013-02-22 15:13:03 -0800290 return latch.getLeader().getId().equals(controllerId);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800291 } catch (Exception e) {
292 //TODO swallow exception?
293 return false;
294 }
295 }
296
297 @Override
Jonathan Hart7bf62172013-02-28 13:17:18 -0800298 public String getControllerId() {
Jonathan Hartbd766972013-02-22 15:13:03 -0800299 return controllerId;
Jonathan Hartbd181b62013-02-17 16:05:38 -0800300 }
301
Jonathan Hartedd6a442013-02-20 15:22:06 -0800302 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800303 public Collection<String> getAllControllers() throws RegistryException {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800304 log.debug("Getting all controllers");
Jonathan Hart1be46262013-02-20 16:43:51 -0800305
Jonathan Hartedd6a442013-02-20 15:22:06 -0800306 List<String> controllers = new ArrayList<String>();
307 for (ChildData data : controllerCache.getCurrentData()){
308
309 String d = null;
310 try {
311 d = new String(data.getData(), "UTF-8");
312 } catch (UnsupportedEncodingException e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800313 throw new RegistryException("Error encoding string", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800314 }
315
316 controllers.add(d);
317 }
318 return controllers;
319 }
320
321 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800322 public void registerController(String id) throws RegistryException {
Jonathan Hartd10008d2013-02-23 17:04:08 -0800323 if (controllerId != null) {
324 throw new RegistryException(
325 "Controller already registered with id " + controllerId);
326 }
Jonathan Hartbd766972013-02-22 15:13:03 -0800327
328 controllerId = id;
Jonathan Hart57080fb2013-02-21 10:55:46 -0800329
Jonathan Hartd10008d2013-02-23 17:04:08 -0800330 byte bytes[] = id.getBytes(Charsets.UTF_8);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800331
332 String path = controllerPath + "/" + id;
333
334 log.info("Registering controller with id {}", id);
335
Jonathan Hart57080fb2013-02-21 10:55:46 -0800336 //Create ephemeral node in controller registry
Jonathan Hartedd6a442013-02-20 15:22:06 -0800337 try {
338 client.create().withProtection().withMode(CreateMode.EPHEMERAL)
339 .forPath(path, bytes);
340 } catch (Exception e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800341 throw new RegistryException("Error contacting the Zookeeper service", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800342 }
343 }
344
345 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800346 public String getControllerForSwitch(long dpid) throws RegistryException {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800347 // TODO Work out how we should store this controller/switch data.
348 // The leader latch might be a index to the /controllers collections
349 // which holds more info on the controller (how to talk to it for example).
350
Jonathan Hartedd6a442013-02-20 15:22:06 -0800351 String strDpid = HexString.toHexString(dpid);
352 LeaderLatch latch = switchLatches.get(strDpid);
353
354 if (latch == null){
355 log.warn("Tried to get controller for non-existent switch");
356 return null;
357 }
358
359 Participant leader = null;
360 try {
361 leader = latch.getLeader();
362 } catch (Exception e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800363 throw new RegistryException("Error contacting the Zookeeper service", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800364 }
365
366 return leader.getId();
367 }
368
369 @Override
370 public Collection<Long> getSwitchesControlledByController(String controllerId) {
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800371 //TODO remove this if not needed
Jonathan Hartbd766972013-02-22 15:13:03 -0800372 throw new RuntimeException("Not yet implemented");
Jonathan Hartedd6a442013-02-20 15:22:06 -0800373 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800374
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800375
376 @Override
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800377 public Map<String, List<ControllerRegistryEntry>> getAllSwitches() {
378 Map<String, List<ControllerRegistryEntry>> data =
379 new HashMap<String, List<ControllerRegistryEntry>>();
380
381 for (Map.Entry<String, PathChildrenCache> entry : switchPathCaches.entrySet()){
382 List<ControllerRegistryEntry> contendingControllers =
383 new ArrayList<ControllerRegistryEntry>();
384
385 if (entry.getValue().getCurrentData().size() < 1){
386 log.info("Switch entry with no leader elections: {}", entry.getKey());
387 continue;
388 }
389
390 for (ChildData d : entry.getValue().getCurrentData()) {
Jonathan Hart97801ac2013-02-26 14:29:16 -0800391
Jonathan Hartd10008d2013-02-23 17:04:08 -0800392 String controllerId = new String(d.getData(), Charsets.UTF_8);
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800393
394 String[] splitted = d.getPath().split("-");
395 int sequenceNumber = Integer.parseInt(splitted[splitted.length - 1]);
396
397 contendingControllers.add(new ControllerRegistryEntry(controllerId, sequenceNumber));
398 }
399
400 Collections.sort(contendingControllers);
401 data.put(entry.getKey(), contendingControllers);
402 }
403 return data;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800404 }
405
Jonathan Hartbd181b62013-02-17 16:05:38 -0800406 /*
407 * IFloodlightModule
408 */
409
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800410 @Override
411 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800412 Collection<Class<? extends IFloodlightService>> l =
413 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800414 l.add(IControllerRegistryService.class);
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800415 return l;
416 }
417
418 @Override
419 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
420 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
421 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800422 m.put(IControllerRegistryService.class, this);
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800423 return m;
424 }
425
426 @Override
427 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800428 Collection<Class<? extends IFloodlightService>> l =
429 new ArrayList<Class<? extends IFloodlightService>>();
430 l.add(IRestApiService.class);
431 return l;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800432 }
433
434 @Override
435 public void init (FloodlightModuleContext context) throws FloodlightModuleException {
Jonathan Hartbd766972013-02-22 15:13:03 -0800436 log.info("Initialising the Zookeeper Registry - Zookeeper connection required");
437
Jonathan Hart97801ac2013-02-26 14:29:16 -0800438 //Read the Zookeeper connection string from the config
439 Map<String, String> configParams = context.getConfigParams(this);
440 String connectionString = configParams.get("connectionString");
441 if (connectionString != null){
442 this.connectionString = connectionString;
Jonathan Hart57080fb2013-02-21 10:55:46 -0800443 }
Jonathan Hart97801ac2013-02-26 14:29:16 -0800444 log.info("Setting Zookeeper connection string to {}", this.connectionString);
Jonathan Hart57080fb2013-02-21 10:55:46 -0800445
Jonathan Hart97801ac2013-02-26 14:29:16 -0800446 restApi = context.getServiceImpl(IRestApiService.class);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800447
448 switchLatches = new HashMap<String, LeaderLatch>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800449 switchCallbacks = new HashMap<String, ControlChangeCallback>();
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800450 switchPathCaches = new HashMap<String, PathChildrenCache>();
Jonathan Hartbd181b62013-02-17 16:05:38 -0800451
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800452 RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
Jonathan Hart97801ac2013-02-26 14:29:16 -0800453 client = CuratorFrameworkFactory.newClient(this.connectionString,
Jonathan Hartcc957a02013-02-26 10:39:04 -0800454 sessionTimeout, connectionTimeout, retryPolicy);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800455
456 client.start();
457
458 client = client.usingNamespace(namespace);
Jonathan Hart97801ac2013-02-26 14:29:16 -0800459
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800460
Jonathan Hartedd6a442013-02-20 15:22:06 -0800461 controllerCache = new PathChildrenCache(client, controllerPath, true);
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800462 switchCache = new PathChildrenCache(client, switchLatchesPath, true);
463 switchCache.getListenable().addListener(switchPathCacheListener);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800464
465 try {
466 controllerCache.start(StartMode.BUILD_INITIAL_CACHE);
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800467
468 //Don't prime the cache, we want a notification for each child node in the path
469 switchCache.start(StartMode.NORMAL);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800470 } catch (Exception e) {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800471 throw new FloodlightModuleException("Error initialising ZookeeperRegistry: "
472 + e.getMessage());
Jonathan Hartedd6a442013-02-20 15:22:06 -0800473 }
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800474 }
475
476 @Override
477 public void startUp (FloodlightModuleContext context) {
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800478 restApi.addRestletRoutable(new RegistryWebRoutable());
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800479 }
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800480}