blob: df3d3368de5f82402fe0ee83074818ee2d783004 [file] [log] [blame]
Hyunsun Mooncb799442016-01-15 20:03:18 -08001/*
Brian O'Connor8e57fd52016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Hyunsun Mooncb799442016-01-15 20:03:18 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
alshabibb4d31712016-06-01 18:51:03 -070016package org.opencord.cordvtn.impl;
Hyunsun Mooncb799442016-01-15 20:03:18 -080017
Hyunsun Moon3ef52492016-06-15 14:56:31 -070018import com.google.common.base.Strings;
Hyunsun Moon126171d2016-02-09 01:55:48 -080019import com.jcraft.jsch.Session;
Hyunsun Mooncb799442016-01-15 20:03:18 -080020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
Hyunsun Moon126171d2016-02-09 01:55:48 -080026import org.onlab.packet.IpAddress;
Hyunsun Mooncb799442016-01-15 20:03:18 -080027import org.onlab.util.KryoNamespace;
28import org.onosproject.cluster.ClusterService;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080029import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
Hyunsun Moon3ef52492016-06-15 14:56:31 -070031import org.onosproject.net.behaviour.BridgeDescription;
32import org.onosproject.net.behaviour.DefaultBridgeDescription;
33import org.onosproject.net.behaviour.InterfaceConfig;
alshabibb4d31712016-06-01 18:51:03 -070034import org.opencord.cordvtn.api.ConnectionHandler;
35import org.opencord.cordvtn.api.CordVtnConfig;
36import org.opencord.cordvtn.api.CordVtnNode;
37import org.opencord.cordvtn.api.CordVtnNodeState;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070038import org.opencord.cordvtn.api.InstanceService;
alshabibb4d31712016-06-01 18:51:03 -070039import org.opencord.cordvtn.api.NetworkAddress;
40import org.opencord.cordvtn.api.SshAccessInfo;
Hyunsun Mooncb799442016-01-15 20:03:18 -080041import org.onosproject.core.ApplicationId;
42import org.onosproject.core.CoreService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080043import org.onosproject.net.ConnectPoint;
Hyunsun Mooncb799442016-01-15 20:03:18 -080044import org.onosproject.net.Device;
45import org.onosproject.net.DeviceId;
Hyunsun Mooncb799442016-01-15 20:03:18 -080046import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070047import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080048import org.onosproject.net.behaviour.BridgeConfig;
49import org.onosproject.net.behaviour.BridgeName;
50import org.onosproject.net.behaviour.ControllerInfo;
51import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080052import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080053import org.onosproject.net.config.NetworkConfigEvent;
54import org.onosproject.net.config.NetworkConfigListener;
55import org.onosproject.net.config.NetworkConfigRegistry;
56import org.onosproject.net.config.NetworkConfigService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080057import org.onosproject.net.device.DeviceAdminService;
58import org.onosproject.net.device.DeviceEvent;
59import org.onosproject.net.device.DeviceListener;
60import org.onosproject.net.device.DeviceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080061import org.onosproject.net.host.HostService;
62import org.onosproject.ovsdb.controller.OvsdbClientService;
63import org.onosproject.ovsdb.controller.OvsdbController;
64import org.onosproject.ovsdb.controller.OvsdbNodeId;
65import org.onosproject.store.serializers.KryoNamespaces;
66import org.onosproject.store.service.ConsistentMap;
Hyunsun Moonff55e812016-03-10 12:40:16 -080067import org.onosproject.store.service.MapEvent;
68import org.onosproject.store.service.MapEventListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080069import org.onosproject.store.service.Serializer;
70import org.onosproject.store.service.StorageService;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080071import org.onosproject.store.service.Versioned;
Hyunsun Mooncb799442016-01-15 20:03:18 -080072import org.slf4j.Logger;
73
Hyunsun Mooncb799442016-01-15 20:03:18 -080074import java.util.List;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080075import java.util.Objects;
Hyunsun Moon126171d2016-02-09 01:55:48 -080076import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080077import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080078import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080079
80import static com.google.common.base.Preconditions.checkNotNull;
81import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
82import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon3ef52492016-06-15 14:56:31 -070083import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Mooncb799442016-01-15 20:03:18 -080084import static org.onosproject.net.Device.Type.SWITCH;
85import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070086import static org.opencord.cordvtn.api.Constants.*;
alshabibb4d31712016-06-01 18:51:03 -070087import static org.opencord.cordvtn.impl.RemoteIpCommandUtil.*;
Hyunsun Mooncb799442016-01-15 20:03:18 -080088import static org.slf4j.LoggerFactory.getLogger;
89
90/**
91 * Reads node information from the network config file and handles the config
92 * update events.
93 * Only a leader controller performs the node addition or deletion.
94 */
95@Component(immediate = true)
96@Service(value = CordVtnNodeManager.class)
97public class CordVtnNodeManager {
98
99 protected final Logger log = getLogger(getClass());
100
101 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
102 .register(KryoNamespaces.API)
103 .register(CordVtnNode.class)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800104 .register(NodeState.class)
105 .register(SshAccessInfo.class)
106 .register(NetworkAddress.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800107
Hyunsun Mooncb799442016-01-15 20:03:18 -0800108 private static final int DPID_BEGIN = 3;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected CoreService coreService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected NetworkConfigRegistry configRegistry;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected NetworkConfigService configService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected StorageService storageService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected DeviceAdminService adminService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700126 protected OvsdbController ovsdbController;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected ClusterService clusterService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800132 protected DeviceService deviceService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected HostService hostService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800138 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700141 protected InstanceService instanceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700144 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800145
Hyunsun Mooncb799442016-01-15 20:03:18 -0800146 private final ExecutorService eventExecutor =
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700147 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn-node", "event-handler"));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800148
149 private final NetworkConfigListener configListener = new InternalConfigListener();
150 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800151 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800152
153 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
154 private final BridgeHandler bridgeHandler = new BridgeHandler();
155
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800156 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800157 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800158 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800159
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800160 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800161
162 INIT {
163 @Override
164 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700165 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800166 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800167 nodeManager.connectOvsdb(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700168 return;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800169 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700170 nodeManager.createIntegrationBridge(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800171 }
172 },
173 BRIDGE_CREATED {
174 @Override
175 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700176 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800177 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800178 nodeManager.connectOvsdb(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700179 return;
180 }
181
182 nodeManager.createTunnelInterface(node);
183 nodeManager.addSystemInterface(node, node.dataIface());
184 if (node.hostMgmtIface().isPresent()) {
185 nodeManager.addSystemInterface(node, node.hostMgmtIface().get());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800186 }
187 }
188 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800189 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800190 @Override
191 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800192 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800193 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800194 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800195 COMPLETE {
196 @Override
197 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
198 nodeManager.postInit(node);
199 }
200 },
201 INCOMPLETE {
202 @Override
203 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
204 }
205 };
206
Hyunsun Mooncb799442016-01-15 20:03:18 -0800207 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
208 }
209
210 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700211 protected void activate() {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700212 appId = coreService.getAppId(CORDVTN_APP_ID);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700213
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800214 localNodeId = clusterService.getLocalNode().id();
215 leadershipService.runForLeadership(appId.name());
216
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800217 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800218 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
219 .withName("cordvtn-nodestore")
220 .withApplicationId(appId)
221 .build();
222
Hyunsun Moonff55e812016-03-10 12:40:16 -0800223 nodeStore.addListener(nodeStoreListener);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800224 deviceService.addListener(deviceListener);
225 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700226
227 log.info("Started");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800228 }
229
230 @Deactivate
231 protected void deactivate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800232 configService.removeListener(configListener);
233 deviceService.removeListener(deviceListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800234 nodeStore.removeListener(nodeStoreListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800235
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800236 leadershipService.withdraw(appId.name());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800237 eventExecutor.shutdown();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700238
239 log.info("Stopped");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800240 }
241
242 /**
Hyunsun Moonff55e812016-03-10 12:40:16 -0800243 * Adds or updates a new node to the service.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800244 *
245 * @param node cordvtn node
246 */
Hyunsun Moonff55e812016-03-10 12:40:16 -0800247 public void addOrUpdateNode(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800248 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800249 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800250 }
251
252 /**
253 * Deletes a node from the service.
254 *
255 * @param node cordvtn node
256 */
257 public void deleteNode(CordVtnNode node) {
258 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700259 OvsdbClientService ovsdbClient = getOvsdbClient(node);
260 if (ovsdbClient != null && ovsdbClient.isConnected()) {
261 ovsdbClient.disconnect();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800262 }
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800263 nodeStore.remove(node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800264 }
265
266 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800267 * Returns node initialization state.
268 *
269 * @param node cordvtn node
270 * @return true if initial node setup is completed, otherwise false
271 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800272 public boolean isNodeInitComplete(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800273 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700274 return getNodeState(node).equals(NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800275 }
276
277 /**
278 * Returns the number of the nodes known to the service.
279 *
280 * @return number of nodes
281 */
282 public int getNodeCount() {
283 return nodeStore.size();
284 }
285
286 /**
287 * Returns all nodes known to the service.
288 *
289 * @return list of nodes
290 */
291 public List<CordVtnNode> getNodes() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700292 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800293 }
294
295 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700296 * Returns all nodes in complete state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800297 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700298 * @return set of nodes
Hyunsun Mooncb799442016-01-15 20:03:18 -0800299 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700300 public Set<CordVtnNode> completeNodes() {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700301 return getNodes().stream().filter(this::isNodeStateComplete)
302 .collect(Collectors.toSet());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800303 }
304
305 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700306 * Returns physical data plane port number of a given device.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800307 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700308 * @param deviceId integration bridge device id
309 * @return port number; null otherwise
Hyunsun Mooncb799442016-01-15 20:03:18 -0800310 */
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700311 public PortNumber dataPort(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700312 CordVtnNode node = nodeByBridgeId(deviceId);
313 if (node == null) {
314 log.warn("Failed to get node for {}", deviceId);
315 return null;
316 }
317 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700318 .filter(p -> portName(p).contains(node.dataIface()) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700319 p.isEnabled())
Hyunsun Mooncb799442016-01-15 20:03:18 -0800320 .findFirst().orElse(null);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700321
322 return port == null ? null : port.number();
323 }
324
325 /**
326 * Returns physical data plane IP address of a given device.
327 *
328 * @param deviceId integration bridge device id
329 * @return ip address; null otherwise
330 */
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700331 public IpAddress dataIp(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700332 CordVtnNode node = nodeByBridgeId(deviceId);
333 if (node == null) {
334 log.warn("Failed to get node for {}", deviceId);
335 return null;
336 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700337 return node.dataIp().ip();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700338 }
339
340 /**
341 * Returns tunnel port number of a given device.
342 *
343 * @param deviceId integration bridge device id
344 * @return port number
345 */
346 public PortNumber tunnelPort(DeviceId deviceId) {
347 Port port = deviceService.getPorts(deviceId).stream()
348 .filter(p -> portName(p).contains(DEFAULT_TUNNEL))
349 .findFirst().orElse(null);
350
351 return port == null ? null : port.number();
352 }
353
354 /**
355 * Returns if current node state saved in nodeStore is COMPLETE or not.
356 *
357 * @param node cordvtn node
358 * @return true if it's complete state, otherwise false
359 */
360 private boolean isNodeStateComplete(CordVtnNode node) {
361 checkNotNull(node);
362
363 // the state saved in nodeStore can be wrong if IP address settings are changed
364 // after the node init has been completed since there's no way to detect it
365 // getNodeState and checkNodeInitState always return correct answer but can be slow
366 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
367 CordVtnNodeState state = versionedNode.value().state();
368 return state != null && state.equals(NodeState.COMPLETE);
369 }
370
371 /**
372 * Initiates node to serve virtual tenant network.
373 *
374 * @param node cordvtn node
375 */
376 private void initNode(CordVtnNode node) {
377 checkNotNull(node);
378
379 NodeState state = (NodeState) node.state();
380 log.debug("Processing node: {} state: {}", node.hostname(), state);
381
382 state.process(this, node);
383 }
384
385 /**
386 * Performs tasks after node initialization.
387 * It disconnects unnecessary OVSDB connection and installs initial flow
388 * rules on the device.
389 *
390 * @param node cordvtn node
391 */
392 private void postInit(CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700393 checkNotNull(node);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700394
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700395 // disconnect OVSDB session once the node bootstrap is done
396 OvsdbClientService ovsdbClient = getOvsdbClient(node);
397 if (ovsdbClient != null && ovsdbClient.isConnected()) {
398 ovsdbClient.disconnect();
399 }
400
401 pipeline.initPipeline(node, dataPort(node.integrationBridgeId()),
402 tunnelPort(node.integrationBridgeId()));
403
404 // adds existing instances to the host list
405 deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700406 .filter(port -> portName(port).startsWith(VPORT_PREFIX) &&
407 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700408 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700409
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700410 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700411 hostService.getHosts().forEach(host -> {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700412 if (deviceService.getPort(
413 host.location().deviceId(),
414 host.location().port()) == null) {
415 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700416 }
417 });
418
419 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800420 }
421
422 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800423 * Sets a new state for a given cordvtn node.
424 *
425 * @param node cordvtn node
426 * @param newState new node state
427 */
428 private void setNodeState(CordVtnNode node, NodeState newState) {
429 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800430 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800431 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800432 }
433
434 /**
435 * Checks current state of a given cordvtn node and returns it.
436 *
437 * @param node cordvtn node
438 * @return node state
439 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800440 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800441 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700442 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800443 return NodeState.INIT;
444 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700445 for (String iface : node.systemIfaces()) {
446 if (!isIfaceCreated(node, iface)) {
447 return NodeState.BRIDGE_CREATED;
448 }
449 }
450 if (!isIpAddressSet(node)) {
451 return NodeState.PORTS_ADDED;
452 }
453 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800454 }
455
456 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800457 * Returns connection state of OVSDB server for a given node.
458 *
459 * @param node cordvtn node
460 * @return true if it is connected, false otherwise
461 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800462 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800463 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800464 OvsdbClientService ovsdbClient = getOvsdbClient(node);
465 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700466 ovsdbClient != null &&
467 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800468 }
469
470 /**
471 * Connects to OVSDB server for a given node.
472 *
473 * @param node cordvtn node
474 */
475 private void connectOvsdb(CordVtnNode node) {
476 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700477 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800478 }
479
480 /**
481 * Returns OVSDB client for a given node.
482 *
483 * @param node cordvtn node
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700484 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800485 */
486 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
487 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700488 OvsdbNodeId ovsdb = new OvsdbNodeId(
489 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
490 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800491 }
492
Hyunsun Mooncb799442016-01-15 20:03:18 -0800493 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700494 Device device = deviceService.getDevice(node.ovsdbId());
495 if (device == null || !device.is(BridgeConfig.class)) {
496 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800497 return;
498 }
499
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700500 List<ControllerInfo> controllers = clusterService.getNodes().stream()
501 .map(controller -> new ControllerInfo(controller.ip(), OF_PORT, "tcp"))
502 .collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800503
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700504 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
505 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
506 .name(INTEGRATION_BRIDGE)
507 .failMode(BridgeDescription.FailMode.SECURE)
508 .datapathId(dpid)
509 .disableInBand()
510 .controllers(controllers)
511 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800512
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700513 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
514 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800515 }
516
Hyunsun Mooncb799442016-01-15 20:03:18 -0800517 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700518 Device device = deviceService.getDevice(node.ovsdbId());
519 if (device == null || !device.is(InterfaceConfig.class)) {
520 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800521 return;
522 }
523
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700524 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
525 .name(DEFAULT_TUNNEL)
526 .type(VXLAN)
527 .enableFlowDst()
528 .enableFlowKey()
529 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800530
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700531 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
532 ifaceConfig.addTunnelInterface(BridgeName.of(INTEGRATION_BRIDGE), tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800533 }
534
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700535 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700536 Session session = connect(node.sshInfo());
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700537 if (session == null || !isInterfaceUp(session, ifaceName)) {
538 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
539 disconnect(session);
540 return;
541 } else {
542 disconnect(session);
543 }
544
545 Device device = deviceService.getDevice(node.ovsdbId());
546 if (!device.is(BridgeConfig.class)) {
547 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700548 return;
549 }
550
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700551 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
552 bridgeConfig.addPort(BridgeName.of(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800553 }
554
555 /**
556 * Flushes IP address from data plane interface and adds data plane IP address
557 * to integration bridge.
558 *
559 * @param node cordvtn node
560 */
561 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700562 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800563 if (session == null) {
564 log.debug("Failed to SSH to {}", node.hostname());
565 return;
566 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700567 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moonf2760522016-03-04 19:24:08 -0800568 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700569 .filter(ip -> !ip.equals(node.dataIp().ip()))
570 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moonf2760522016-03-04 19:24:08 -0800571
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700572 boolean result = flushIp(session, node.dataIface()) &&
573 setInterfaceUp(session, node.dataIface()) &&
574 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
575 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
576 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800577
Hyunsun Moon479b7752016-05-06 20:13:28 -0700578 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800579 if (result) {
580 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800581 }
582 }
583
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700584 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
585 return deviceService.getDevice(node.integrationBridgeId()) != null &&
586 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800587 }
588
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700589 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
590 if (Strings.isNullOrEmpty(ifaceName)) {
591 return false;
592 }
593 return deviceService.getPorts(node.integrationBridgeId()).stream()
594 .filter(p -> portName(p).contains(ifaceName) &&
595 p.isEnabled())
596 .findAny()
597 .isPresent();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800598 }
599
600 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800601 * Checks if the IP addresses are correctly set.
602 *
603 * @param node cordvtn node
604 * @return true if the IP is set, false otherwise
605 */
606 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700607 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800608 if (session == null) {
609 log.debug("Failed to SSH to {}", node.hostname());
610 return false;
611 }
612
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700613 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
614 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
615 isInterfaceUp(session, node.dataIface()) &&
616 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800617 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700618 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800619
Hyunsun Moon479b7752016-05-06 20:13:28 -0700620 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800621 return result;
622 }
623
624 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800625 * Returns connect point of a given port.
626 *
627 * @param port port
628 * @return connect point
629 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700630 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800631 return new ConnectPoint(port.element().id(), port.number());
632 }
633
634 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700635 * Returns cordvtn node associated with a given OVSDB device.
636 *
637 * @param ovsdbId OVSDB device id
638 * @return cordvtn node, null if it fails to find the node
639 */
640 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
641 return getNodes().stream()
642 .filter(node -> node.ovsdbId().equals(ovsdbId))
643 .findFirst().orElse(null);
644 }
645
646 /**
647 * Returns cordvtn node associated with a given integration bridge.
648 *
649 * @param bridgeId device id of integration bridge
650 * @return cordvtn node, null if it fails to find the node
651 */
652 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
653 return getNodes().stream()
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700654 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700655 .findFirst().orElse(null);
656 }
657
658 /**
659 * Returns port name.
660 *
661 * @param port port
662 * @return port name
663 */
664 private String portName(Port port) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700665 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700666 }
667
Hyunsun Mooncb799442016-01-15 20:03:18 -0800668 private class OvsdbHandler implements ConnectionHandler<Device> {
669
670 @Override
671 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700672 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800673 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800674 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800675 } else {
676 log.debug("{} is detected on unregistered node, ignore it.", device.id());
677 }
678 }
679
680 @Override
681 public void disconnected(Device device) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700682 log.debug("Device {} is disconnected", device.id());
683 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800684 }
685 }
686
687 private class BridgeHandler implements ConnectionHandler<Device> {
688
689 @Override
690 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700691 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800692 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800693 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800694 } else {
695 log.debug("{} is detected on unregistered node, ignore it.", device.id());
696 }
697 }
698
699 @Override
700 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700701 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800702 if (node != null) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700703 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800704 setNodeState(node, NodeState.INCOMPLETE);
705 }
706 }
707
708 /**
709 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800710 * If the added port is tunnel or data plane interface, proceed to the remaining
711 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800712 *
713 * @param port port
714 */
715 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700716 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
717 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800718
719 if (node == null) {
720 log.debug("{} is added to unregistered node, ignore it.", portName);
721 return;
722 }
723
Hyunsun Moonff55e812016-03-10 12:40:16 -0800724 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800725
726 if (portName.startsWith(VPORT_PREFIX)) {
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800727 if (isNodeStateComplete(node)) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700728 instanceService.addInstance(connectPoint(port));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800729 } else {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700730 log.warn("VM is detected on incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800731 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700732 } else if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800733 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800734 }
735 }
736
737 /**
738 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800739 * If the removed port is tunnel or data plane interface, proceed to the remaining
740 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800741 *
742 * @param port port
743 */
744 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700745 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
746 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800747
748 if (node == null) {
749 return;
750 }
751
Hyunsun Moonff55e812016-03-10 12:40:16 -0800752 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800753
754 if (portName.startsWith(VPORT_PREFIX)) {
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800755 if (isNodeStateComplete(node)) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700756 instanceService.removeInstance(connectPoint(port));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800757 } else {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700758 log.warn("VM is vanished from incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800759 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700760 } else if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800761 setNodeState(node, NodeState.INCOMPLETE);
762 }
763 }
764 }
765
766 private class InternalDeviceListener implements DeviceListener {
767
768 @Override
769 public void event(DeviceEvent event) {
770
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800771 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
772 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800773 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800774 return;
775 }
776
Hyunsun Mooncb799442016-01-15 20:03:18 -0800777 Device device = event.subject();
778 ConnectionHandler<Device> handler =
779 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
780
781 switch (event.type()) {
782 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800783 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800784 break;
785 case PORT_UPDATED:
786 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800787 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800788 }
789 break;
790 case DEVICE_ADDED:
791 case DEVICE_AVAILABILITY_CHANGED:
792 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800793 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800794 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800795 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800796 }
797 break;
798 default:
799 break;
800 }
801 }
802 }
803
804 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800805 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800806 */
807 private void readConfiguration() {
808 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800809 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800810 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800811 return;
812 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800813 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800814 }
815
816 private class InternalConfigListener implements NetworkConfigListener {
817
818 @Override
819 public void event(NetworkConfigEvent event) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800820 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
821 if (!Objects.equals(localNodeId, leaderNodeId)) {
822 // do not allow to proceed without leadership
823 return;
824 }
825
Hyunsun Mooncb799442016-01-15 20:03:18 -0800826 if (!event.configClass().equals(CordVtnConfig.class)) {
827 return;
828 }
829
830 switch (event.type()) {
831 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800832 case CONFIG_UPDATED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800833 eventExecutor.execute(CordVtnNodeManager.this::readConfiguration);
834 break;
835 default:
836 break;
837 }
838 }
839 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800840
841 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
842
843 @Override
844 public void event(MapEvent<String, CordVtnNode> event) {
845 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
846 if (!Objects.equals(localNodeId, leaderNodeId)) {
847 // do not allow to proceed without leadership
848 return;
849 }
850
851 CordVtnNode oldNode;
852 CordVtnNode newNode;
853
854 switch (event.type()) {
855 case UPDATE:
856 oldNode = event.oldValue().value();
857 newNode = event.newValue().value();
858
Hyunsun Moon479b7752016-05-06 20:13:28 -0700859 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800860 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800861 log.debug("New node: {}", newNode);
862 }
Hyunsun Moon479b7752016-05-06 20:13:28 -0700863 // performs init procedure even if the node is not changed
864 // for robustness since it's no harm to run init procedure
865 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -0800866 eventExecutor.execute(() -> initNode(newNode));
867 break;
868 case INSERT:
869 newNode = event.newValue().value();
870 log.info("Added {}", newNode.hostname());
871 eventExecutor.execute(() -> initNode(newNode));
872 break;
873 case REMOVE:
874 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700875 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800876 break;
877 default:
878 break;
879 }
880 }
881 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800882}