blob: c45fef322ed8e450b507cb5b105a5784e69da65f [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 Moonacbc8ef2016-06-21 17:58:45 -070031import org.onosproject.net.AnnotationKeys;
Hyunsun Moon3ef52492016-06-15 14:56:31 -070032import org.onosproject.net.behaviour.BridgeDescription;
33import org.onosproject.net.behaviour.DefaultBridgeDescription;
34import org.onosproject.net.behaviour.InterfaceConfig;
alshabibb4d31712016-06-01 18:51:03 -070035import org.opencord.cordvtn.api.ConnectionHandler;
36import org.opencord.cordvtn.api.CordVtnConfig;
37import org.opencord.cordvtn.api.CordVtnNode;
38import org.opencord.cordvtn.api.CordVtnNodeState;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070039import org.opencord.cordvtn.api.InstanceService;
alshabibb4d31712016-06-01 18:51:03 -070040import org.opencord.cordvtn.api.NetworkAddress;
41import org.opencord.cordvtn.api.SshAccessInfo;
Hyunsun Mooncb799442016-01-15 20:03:18 -080042import org.onosproject.core.ApplicationId;
43import org.onosproject.core.CoreService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080044import org.onosproject.net.ConnectPoint;
Hyunsun Mooncb799442016-01-15 20:03:18 -080045import org.onosproject.net.Device;
46import org.onosproject.net.DeviceId;
Hyunsun Mooncb799442016-01-15 20:03:18 -080047import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070048import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080049import org.onosproject.net.behaviour.BridgeConfig;
50import org.onosproject.net.behaviour.BridgeName;
51import org.onosproject.net.behaviour.ControllerInfo;
52import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080053import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080054import org.onosproject.net.config.NetworkConfigEvent;
55import org.onosproject.net.config.NetworkConfigListener;
56import org.onosproject.net.config.NetworkConfigRegistry;
57import org.onosproject.net.config.NetworkConfigService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080058import org.onosproject.net.device.DeviceAdminService;
59import org.onosproject.net.device.DeviceEvent;
60import org.onosproject.net.device.DeviceListener;
61import org.onosproject.net.device.DeviceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080062import org.onosproject.net.host.HostService;
63import org.onosproject.ovsdb.controller.OvsdbClientService;
64import org.onosproject.ovsdb.controller.OvsdbController;
65import org.onosproject.ovsdb.controller.OvsdbNodeId;
66import org.onosproject.store.serializers.KryoNamespaces;
67import org.onosproject.store.service.ConsistentMap;
Hyunsun Moonff55e812016-03-10 12:40:16 -080068import org.onosproject.store.service.MapEvent;
69import org.onosproject.store.service.MapEventListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080070import org.onosproject.store.service.Serializer;
71import org.onosproject.store.service.StorageService;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080072import org.onosproject.store.service.Versioned;
Hyunsun Mooncb799442016-01-15 20:03:18 -080073import org.slf4j.Logger;
74
Hyunsun Mooncb799442016-01-15 20:03:18 -080075import java.util.List;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080076import java.util.Objects;
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -070077import java.util.Optional;
Hyunsun Moon126171d2016-02-09 01:55:48 -080078import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080079import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080080import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080081
82import static com.google.common.base.Preconditions.checkNotNull;
83import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
84import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon3ef52492016-06-15 14:56:31 -070085import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Mooncb799442016-01-15 20:03:18 -080086import static org.onosproject.net.Device.Type.SWITCH;
87import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070088import static org.opencord.cordvtn.api.Constants.*;
alshabibb4d31712016-06-01 18:51:03 -070089import static org.opencord.cordvtn.impl.RemoteIpCommandUtil.*;
Hyunsun Mooncb799442016-01-15 20:03:18 -080090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
93 * Reads node information from the network config file and handles the config
94 * update events.
95 * Only a leader controller performs the node addition or deletion.
96 */
97@Component(immediate = true)
98@Service(value = CordVtnNodeManager.class)
99public class CordVtnNodeManager {
100
101 protected final Logger log = getLogger(getClass());
102
103 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
104 .register(KryoNamespaces.API)
105 .register(CordVtnNode.class)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800106 .register(NodeState.class)
107 .register(SshAccessInfo.class)
108 .register(NetworkAddress.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800109
Hyunsun Mooncb799442016-01-15 20:03:18 -0800110 private static final int DPID_BEGIN = 3;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected CoreService coreService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected NetworkConfigRegistry configRegistry;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected NetworkConfigService configService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected StorageService storageService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected DeviceAdminService adminService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700128 protected OvsdbController ovsdbController;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected ClusterService clusterService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800134 protected DeviceService deviceService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected HostService hostService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800140 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700143 protected InstanceService instanceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700146 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800147
Hyunsun Mooncb799442016-01-15 20:03:18 -0800148 private final ExecutorService eventExecutor =
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700149 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn-node", "event-handler"));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800150
151 private final NetworkConfigListener configListener = new InternalConfigListener();
152 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800153 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800154
155 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
156 private final BridgeHandler bridgeHandler = new BridgeHandler();
157
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800158 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800159 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800160 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800161
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800162 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800163
164 INIT {
165 @Override
166 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700167 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800168 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800169 nodeManager.connectOvsdb(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700170 return;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800171 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700172 nodeManager.createIntegrationBridge(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800173 }
174 },
175 BRIDGE_CREATED {
176 @Override
177 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700178 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800179 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800180 nodeManager.connectOvsdb(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700181 return;
182 }
183
184 nodeManager.createTunnelInterface(node);
185 nodeManager.addSystemInterface(node, node.dataIface());
186 if (node.hostMgmtIface().isPresent()) {
187 nodeManager.addSystemInterface(node, node.hostMgmtIface().get());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800188 }
189 }
190 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800191 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800192 @Override
193 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800194 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800195 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800196 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800197 COMPLETE {
198 @Override
199 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
200 nodeManager.postInit(node);
201 }
202 },
203 INCOMPLETE {
204 @Override
205 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
206 }
207 };
208
Hyunsun Mooncb799442016-01-15 20:03:18 -0800209 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
210 }
211
212 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700213 protected void activate() {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700214 appId = coreService.getAppId(CORDVTN_APP_ID);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700215
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800216 localNodeId = clusterService.getLocalNode().id();
217 leadershipService.runForLeadership(appId.name());
218
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800219 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800220 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
221 .withName("cordvtn-nodestore")
222 .withApplicationId(appId)
223 .build();
224
Hyunsun Moonff55e812016-03-10 12:40:16 -0800225 nodeStore.addListener(nodeStoreListener);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800226 deviceService.addListener(deviceListener);
227 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700228
229 log.info("Started");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800230 }
231
232 @Deactivate
233 protected void deactivate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800234 configService.removeListener(configListener);
235 deviceService.removeListener(deviceListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800236 nodeStore.removeListener(nodeStoreListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800237
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800238 leadershipService.withdraw(appId.name());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800239 eventExecutor.shutdown();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700240
241 log.info("Stopped");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800242 }
243
244 /**
Hyunsun Moonff55e812016-03-10 12:40:16 -0800245 * Adds or updates a new node to the service.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800246 *
247 * @param node cordvtn node
248 */
Hyunsun Moonff55e812016-03-10 12:40:16 -0800249 public void addOrUpdateNode(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800250 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800251 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800252 }
253
254 /**
255 * Deletes a node from the service.
256 *
257 * @param node cordvtn node
258 */
259 public void deleteNode(CordVtnNode node) {
260 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700261 OvsdbClientService ovsdbClient = getOvsdbClient(node);
262 if (ovsdbClient != null && ovsdbClient.isConnected()) {
263 ovsdbClient.disconnect();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800264 }
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800265 nodeStore.remove(node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800266 }
267
268 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800269 * Returns node initialization state.
270 *
271 * @param node cordvtn node
272 * @return true if initial node setup is completed, otherwise false
273 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800274 public boolean isNodeInitComplete(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800275 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700276 return getNodeState(node).equals(NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800277 }
278
279 /**
280 * Returns the number of the nodes known to the service.
281 *
282 * @return number of nodes
283 */
284 public int getNodeCount() {
285 return nodeStore.size();
286 }
287
288 /**
289 * Returns all nodes known to the service.
290 *
291 * @return list of nodes
292 */
293 public List<CordVtnNode> getNodes() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700294 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800295 }
296
297 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700298 * Returns all nodes in complete state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800299 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700300 * @return set of nodes
Hyunsun Mooncb799442016-01-15 20:03:18 -0800301 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700302 public Set<CordVtnNode> completeNodes() {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700303 return getNodes().stream().filter(this::isNodeStateComplete)
304 .collect(Collectors.toSet());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800305 }
306
307 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700308 * Returns physical data plane port number of a given device.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800309 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700310 * @param deviceId integration bridge device id
311 * @return port number; null otherwise
Hyunsun Mooncb799442016-01-15 20:03:18 -0800312 */
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700313 public PortNumber dataPort(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700314 CordVtnNode node = nodeByBridgeId(deviceId);
315 if (node == null) {
316 log.warn("Failed to get node for {}", deviceId);
317 return null;
318 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700319
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700320 Optional<PortNumber> port = getPortNumber(deviceId, node.dataIface());
321 return port.isPresent() ? port.get() : null;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700322 }
323
324 /**
325 * Returns physical data plane IP address of a given device.
326 *
327 * @param deviceId integration bridge device id
328 * @return ip address; null otherwise
329 */
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700330 public IpAddress dataIp(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700331 CordVtnNode node = nodeByBridgeId(deviceId);
332 if (node == null) {
333 log.warn("Failed to get node for {}", deviceId);
334 return null;
335 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700336 return node.dataIp().ip();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700337 }
338
339 /**
340 * Returns tunnel port number of a given device.
341 *
342 * @param deviceId integration bridge device id
343 * @return port number
344 */
345 public PortNumber tunnelPort(DeviceId deviceId) {
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700346 Optional<PortNumber> port = getPortNumber(deviceId, DEFAULT_TUNNEL);
347 return port.isPresent() ? port.get() : null;
348 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700349
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700350 /**
351 * Returns host management interface port number if exists.
352 *
353 * @param deviceId integration bridge device id
354 * @return port number; null if it does not exist
355 */
356 public PortNumber hostManagementPort(DeviceId deviceId) {
357 CordVtnNode node = nodeByBridgeId(deviceId);
358 if (node == null) {
359 log.warn("Failed to get node for {}", deviceId);
360 return null;
361 }
362
363 if (node.hostMgmtIface().isPresent()) {
364 Optional<PortNumber> port = getPortNumber(deviceId, node.hostMgmtIface().get());
365 return port.isPresent() ? port.get() : null;
366 } else {
367 return null;
368 }
369 }
370
371 private Optional<PortNumber> getPortNumber(DeviceId deviceId, String portName) {
372 PortNumber port = deviceService.getPorts(deviceId).stream()
373 .filter(p -> p.annotations().value(AnnotationKeys.PORT_NAME).equals(portName) &&
374 p.isEnabled())
375 .map(Port::number)
376 .findAny()
377 .orElse(null);
378 return Optional.ofNullable(port);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700379 }
380
381 /**
382 * Returns if current node state saved in nodeStore is COMPLETE or not.
383 *
384 * @param node cordvtn node
385 * @return true if it's complete state, otherwise false
386 */
387 private boolean isNodeStateComplete(CordVtnNode node) {
388 checkNotNull(node);
389
390 // the state saved in nodeStore can be wrong if IP address settings are changed
391 // after the node init has been completed since there's no way to detect it
392 // getNodeState and checkNodeInitState always return correct answer but can be slow
393 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
394 CordVtnNodeState state = versionedNode.value().state();
395 return state != null && state.equals(NodeState.COMPLETE);
396 }
397
398 /**
399 * Initiates node to serve virtual tenant network.
400 *
401 * @param node cordvtn node
402 */
403 private void initNode(CordVtnNode node) {
404 checkNotNull(node);
405
406 NodeState state = (NodeState) node.state();
407 log.debug("Processing node: {} state: {}", node.hostname(), state);
408
409 state.process(this, node);
410 }
411
412 /**
413 * Performs tasks after node initialization.
414 * It disconnects unnecessary OVSDB connection and installs initial flow
415 * rules on the device.
416 *
417 * @param node cordvtn node
418 */
419 private void postInit(CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700420 checkNotNull(node);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700421
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700422 // disconnect OVSDB session once the node bootstrap is done
423 OvsdbClientService ovsdbClient = getOvsdbClient(node);
424 if (ovsdbClient != null && ovsdbClient.isConnected()) {
425 ovsdbClient.disconnect();
426 }
427
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700428 pipeline.initPipeline(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700429
430 // adds existing instances to the host list
431 deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moonfb417942016-06-23 14:48:20 -0700432 .filter(port -> portName(port).startsWith(VPORT_PREFIX) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700433 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700434 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700435
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700436 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700437 hostService.getHosts().forEach(host -> {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700438 if (deviceService.getPort(
439 host.location().deviceId(),
440 host.location().port()) == null) {
441 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700442 }
443 });
444
445 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800446 }
447
448 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800449 * Sets a new state for a given cordvtn node.
450 *
451 * @param node cordvtn node
452 * @param newState new node state
453 */
454 private void setNodeState(CordVtnNode node, NodeState newState) {
455 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800456 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800457 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800458 }
459
460 /**
461 * Checks current state of a given cordvtn node and returns it.
462 *
463 * @param node cordvtn node
464 * @return node state
465 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800466 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800467 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700468 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800469 return NodeState.INIT;
470 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700471 for (String iface : node.systemIfaces()) {
472 if (!isIfaceCreated(node, iface)) {
473 return NodeState.BRIDGE_CREATED;
474 }
475 }
476 if (!isIpAddressSet(node)) {
477 return NodeState.PORTS_ADDED;
478 }
479 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800480 }
481
482 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800483 * Returns connection state of OVSDB server for a given node.
484 *
485 * @param node cordvtn node
486 * @return true if it is connected, false otherwise
487 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800488 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800489 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800490 OvsdbClientService ovsdbClient = getOvsdbClient(node);
491 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700492 ovsdbClient != null &&
493 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800494 }
495
496 /**
497 * Connects to OVSDB server for a given node.
498 *
499 * @param node cordvtn node
500 */
501 private void connectOvsdb(CordVtnNode node) {
502 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700503 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800504 }
505
506 /**
507 * Returns OVSDB client for a given node.
508 *
509 * @param node cordvtn node
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700510 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800511 */
512 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
513 checkNotNull(node);
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700514 OvsdbNodeId ovsdb = new OvsdbNodeId(
515 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
516 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800517 }
518
Hyunsun Mooncb799442016-01-15 20:03:18 -0800519 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700520 Device device = deviceService.getDevice(node.ovsdbId());
521 if (device == null || !device.is(BridgeConfig.class)) {
522 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800523 return;
524 }
525
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700526 List<ControllerInfo> controllers = clusterService.getNodes().stream()
527 .map(controller -> new ControllerInfo(controller.ip(), OF_PORT, "tcp"))
528 .collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800529
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700530 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
531 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
532 .name(INTEGRATION_BRIDGE)
533 .failMode(BridgeDescription.FailMode.SECURE)
534 .datapathId(dpid)
535 .disableInBand()
536 .controllers(controllers)
537 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800538
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700539 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
540 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800541 }
542
Hyunsun Mooncb799442016-01-15 20:03:18 -0800543 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700544 Device device = deviceService.getDevice(node.ovsdbId());
545 if (device == null || !device.is(InterfaceConfig.class)) {
546 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800547 return;
548 }
549
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700550 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
551 .name(DEFAULT_TUNNEL)
552 .type(VXLAN)
553 .enableFlowDst()
554 .enableFlowKey()
555 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800556
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700557 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
558 ifaceConfig.addTunnelInterface(BridgeName.of(INTEGRATION_BRIDGE), tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800559 }
560
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700561 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700562 Session session = connect(node.sshInfo());
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700563 if (session == null || !isInterfaceUp(session, ifaceName)) {
564 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
565 disconnect(session);
566 return;
567 } else {
568 disconnect(session);
569 }
570
571 Device device = deviceService.getDevice(node.ovsdbId());
572 if (!device.is(BridgeConfig.class)) {
573 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700574 return;
575 }
576
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700577 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
578 bridgeConfig.addPort(BridgeName.of(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800579 }
580
581 /**
582 * Flushes IP address from data plane interface and adds data plane IP address
583 * to integration bridge.
584 *
585 * @param node cordvtn node
586 */
587 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700588 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800589 if (session == null) {
590 log.debug("Failed to SSH to {}", node.hostname());
591 return;
592 }
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700593 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moonf2760522016-03-04 19:24:08 -0800594 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700595 .filter(ip -> !ip.equals(node.dataIp().ip()))
596 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moonf2760522016-03-04 19:24:08 -0800597
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700598 boolean result = flushIp(session, node.dataIface()) &&
599 setInterfaceUp(session, node.dataIface()) &&
600 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
601 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
602 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800603
Hyunsun Moon479b7752016-05-06 20:13:28 -0700604 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800605 if (result) {
606 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800607 }
608 }
609
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700610 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
611 return deviceService.getDevice(node.integrationBridgeId()) != null &&
612 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800613 }
614
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700615 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
616 if (Strings.isNullOrEmpty(ifaceName)) {
617 return false;
618 }
619 return deviceService.getPorts(node.integrationBridgeId()).stream()
620 .filter(p -> portName(p).contains(ifaceName) &&
621 p.isEnabled())
622 .findAny()
623 .isPresent();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800624 }
625
626 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800627 * Checks if the IP addresses are correctly set.
628 *
629 * @param node cordvtn node
630 * @return true if the IP is set, false otherwise
631 */
632 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700633 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800634 if (session == null) {
635 log.debug("Failed to SSH to {}", node.hostname());
636 return false;
637 }
638
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700639 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
640 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
641 isInterfaceUp(session, node.dataIface()) &&
642 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800643 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700644 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800645
Hyunsun Moon479b7752016-05-06 20:13:28 -0700646 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800647 return result;
648 }
649
650 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800651 * Returns connect point of a given port.
652 *
653 * @param port port
654 * @return connect point
655 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700656 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800657 return new ConnectPoint(port.element().id(), port.number());
658 }
659
660 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700661 * Returns cordvtn node associated with a given OVSDB device.
662 *
663 * @param ovsdbId OVSDB device id
664 * @return cordvtn node, null if it fails to find the node
665 */
666 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
667 return getNodes().stream()
668 .filter(node -> node.ovsdbId().equals(ovsdbId))
669 .findFirst().orElse(null);
670 }
671
672 /**
673 * Returns cordvtn node associated with a given integration bridge.
674 *
675 * @param bridgeId device id of integration bridge
676 * @return cordvtn node, null if it fails to find the node
677 */
678 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
679 return getNodes().stream()
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700680 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700681 .findFirst().orElse(null);
682 }
683
684 /**
685 * Returns port name.
686 *
687 * @param port port
688 * @return port name
689 */
690 private String portName(Port port) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700691 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700692 }
693
Hyunsun Mooncb799442016-01-15 20:03:18 -0800694 private class OvsdbHandler implements ConnectionHandler<Device> {
695
696 @Override
697 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700698 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800699 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800700 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800701 } else {
702 log.debug("{} is detected on unregistered node, ignore it.", device.id());
703 }
704 }
705
706 @Override
707 public void disconnected(Device device) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700708 log.debug("Device {} is disconnected", device.id());
709 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800710 }
711 }
712
713 private class BridgeHandler implements ConnectionHandler<Device> {
714
715 @Override
716 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700717 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800718 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800719 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800720 } else {
721 log.debug("{} is detected on unregistered node, ignore it.", device.id());
722 }
723 }
724
725 @Override
726 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700727 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800728 if (node != null) {
Hyunsun Moon3ef52492016-06-15 14:56:31 -0700729 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800730 setNodeState(node, NodeState.INCOMPLETE);
731 }
732 }
733
734 /**
735 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800736 * If the added port is tunnel or data plane interface, proceed to the remaining
737 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800738 *
739 * @param port port
740 */
741 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700742 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
743 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800744
745 if (node == null) {
746 log.debug("{} is added to unregistered node, ignore it.", portName);
747 return;
748 }
749
Hyunsun Moonff55e812016-03-10 12:40:16 -0800750 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800751
Hyunsun Moonfb417942016-06-23 14:48:20 -0700752 if (portName.startsWith(VPORT_PREFIX)) {
753 if (isNodeStateComplete(node)) {
754 instanceService.addInstance(connectPoint(port));
755 } else {
756 log.warn("VM is detected on incomplete node, ignore it.", portName);
757 }
758 } else if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800759 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800760 }
761 }
762
763 /**
764 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800765 * If the removed port is tunnel or data plane interface, proceed to the remaining
766 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800767 *
768 * @param port port
769 */
770 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700771 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
772 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800773
774 if (node == null) {
775 return;
776 }
777
Hyunsun Moonff55e812016-03-10 12:40:16 -0800778 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800779
Hyunsun Moonfb417942016-06-23 14:48:20 -0700780 if (portName.startsWith(VPORT_PREFIX)) {
781 if (isNodeStateComplete(node)) {
782 instanceService.removeInstance(connectPoint(port));
783 } else {
784 log.warn("VM is vanished from incomplete node, ignore it.", portName);
785 }
786 } else if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800787 setNodeState(node, NodeState.INCOMPLETE);
788 }
789 }
790 }
791
792 private class InternalDeviceListener implements DeviceListener {
793
794 @Override
795 public void event(DeviceEvent event) {
796
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800797 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
798 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800799 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800800 return;
801 }
802
Hyunsun Mooncb799442016-01-15 20:03:18 -0800803 Device device = event.subject();
804 ConnectionHandler<Device> handler =
805 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
806
807 switch (event.type()) {
808 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800809 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800810 break;
811 case PORT_UPDATED:
812 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800813 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800814 }
815 break;
816 case DEVICE_ADDED:
817 case DEVICE_AVAILABILITY_CHANGED:
818 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800819 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800820 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800821 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800822 }
823 break;
824 default:
825 break;
826 }
827 }
828 }
829
830 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800831 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800832 */
833 private void readConfiguration() {
834 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800835 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800836 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800837 return;
838 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800839 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800840 }
841
842 private class InternalConfigListener implements NetworkConfigListener {
843
844 @Override
845 public void event(NetworkConfigEvent event) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800846 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
847 if (!Objects.equals(localNodeId, leaderNodeId)) {
848 // do not allow to proceed without leadership
849 return;
850 }
851
Hyunsun Mooncb799442016-01-15 20:03:18 -0800852 if (!event.configClass().equals(CordVtnConfig.class)) {
853 return;
854 }
855
856 switch (event.type()) {
857 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800858 case CONFIG_UPDATED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800859 eventExecutor.execute(CordVtnNodeManager.this::readConfiguration);
860 break;
861 default:
862 break;
863 }
864 }
865 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800866
867 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
868
869 @Override
870 public void event(MapEvent<String, CordVtnNode> event) {
871 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
872 if (!Objects.equals(localNodeId, leaderNodeId)) {
873 // do not allow to proceed without leadership
874 return;
875 }
876
877 CordVtnNode oldNode;
878 CordVtnNode newNode;
879
880 switch (event.type()) {
881 case UPDATE:
882 oldNode = event.oldValue().value();
883 newNode = event.newValue().value();
884
Hyunsun Moon479b7752016-05-06 20:13:28 -0700885 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800886 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800887 log.debug("New node: {}", newNode);
888 }
Hyunsun Moon479b7752016-05-06 20:13:28 -0700889 // performs init procedure even if the node is not changed
890 // for robustness since it's no harm to run init procedure
891 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -0800892 eventExecutor.execute(() -> initNode(newNode));
893 break;
894 case INSERT:
895 newNode = event.newValue().value();
896 log.info("Added {}", newNode.hostname());
897 eventExecutor.execute(() -> initNode(newNode));
898 break;
899 case REMOVE:
900 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700901 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800902 break;
903 default:
904 break;
905 }
906 }
907 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800908}