blob: a645ec5c28b32fd1cf2172ff291dea5bdbfe8f98 [file] [log] [blame]
Daniel Parka7d6e9f2016-01-18 17:54:14 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Daniel Parka7d6e9f2016-01-18 17:54:14 +09003 *
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 */
16package org.onosproject.openstacknode;
17
Daniel Parka7d6e9f2016-01-18 17:54:14 +090018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
24import org.onlab.util.ItemNotFoundException;
25import org.onlab.util.KryoNamespace;
26import org.onosproject.cluster.ClusterService;
Daniel Parkad21c572016-03-09 10:18:24 +090027import org.onosproject.cluster.LeadershipService;
28import org.onosproject.cluster.NodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090031import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.Port;
34import org.onosproject.net.behaviour.BridgeConfig;
Hyunsun Moon1251e192016-06-07 16:57:05 -070035import org.onosproject.net.behaviour.BridgeDescription;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090036import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moon1251e192016-06-07 16:57:05 -070037import org.onosproject.net.behaviour.DefaultBridgeDescription;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090038import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Moondd14e8e2016-06-09 16:17:32 -070039import org.onosproject.net.behaviour.InterfaceConfig;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090040import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Moondd14e8e2016-06-09 16:17:32 -070041import org.onosproject.net.behaviour.TunnelEndPoints;
42import org.onosproject.net.behaviour.TunnelKeys;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090043import org.onosproject.net.config.ConfigFactory;
44import org.onosproject.net.config.NetworkConfigEvent;
45import org.onosproject.net.config.NetworkConfigListener;
46import org.onosproject.net.config.NetworkConfigRegistry;
47import org.onosproject.net.config.NetworkConfigService;
48import org.onosproject.net.config.basics.SubjectFactories;
49import org.onosproject.net.device.DeviceAdminService;
50import org.onosproject.net.device.DeviceEvent;
51import org.onosproject.net.device.DeviceListener;
52import org.onosproject.net.device.DeviceService;
53import org.onosproject.net.driver.DriverHandler;
54import org.onosproject.net.driver.DriverService;
55import org.onosproject.ovsdb.controller.OvsdbClientService;
56import org.onosproject.ovsdb.controller.OvsdbController;
57import org.onosproject.ovsdb.controller.OvsdbNodeId;
58import org.onosproject.store.serializers.KryoNamespaces;
59import org.onosproject.store.service.ConsistentMap;
60import org.onosproject.store.service.Serializer;
61import org.onosproject.store.service.StorageService;
62import org.slf4j.Logger;
63
Daniel Parkad21c572016-03-09 10:18:24 +090064import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090065import static org.onlab.util.Tools.groupedThreads;
66import static org.onosproject.net.Device.Type.SWITCH;
67import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
68import static org.slf4j.LoggerFactory.getLogger;
69
70import java.util.ArrayList;
71import java.util.List;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090072import java.util.concurrent.ExecutorService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090073import java.util.stream.Collectors;
74
75import static com.google.common.base.Preconditions.checkNotNull;
76
77
78/**
79 * Initializes devices in compute/gateway nodes according to there type.
80 */
81@Component(immediate = true)
82@Service
83public class OpenstackNodeManager implements OpenstackNodeService {
84 protected final Logger log = getLogger(getClass());
Daniel Parka7d6e9f2016-01-18 17:54:14 +090085 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
86 .register(KryoNamespaces.API)
87 .register(OpenstackNode.class)
88 .register(OpenstackNodeType.class)
89 .register(NodeState.class);
90 private static final String DEFAULT_BRIDGE = "br-int";
91 private static final String DEFAULT_TUNNEL = "vxlan";
92 private static final String PORT_NAME = "portName";
93 private static final String OPENSTACK_NODESTORE = "openstacknode-nodestore";
94 private static final String OPENSTACK_NODEMANAGER_ID = "org.onosproject.openstacknode";
95
Daniel Parka7d6e9f2016-01-18 17:54:14 +090096 private static final int DPID_BEGIN = 3;
97 private static final int OFPORT = 6653;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected CoreService coreService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected DeviceService deviceService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected OvsdbController controller;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected ClusterService clusterService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected DriverService driverService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected DeviceAdminService adminService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected StorageService storageService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected NetworkConfigService configService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected NetworkConfigRegistry configRegistry;
125
Daniel Parkad21c572016-03-09 10:18:24 +0900126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected LeadershipService leadershipService;
128
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900129 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
130 private final BridgeHandler bridgeHandler = new BridgeHandler();
131 private final NetworkConfigListener configListener = new InternalConfigListener();
132 private final ConfigFactory configFactory =
133 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, OpenstackNodeConfig.class, "openstacknode") {
134 @Override
135 public OpenstackNodeConfig createConfig() {
136 return new OpenstackNodeConfig();
137 }
138 };
139
Daniel Parkad21c572016-03-09 10:18:24 +0900140 private final ExecutorService eventExecutor =
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700141 newSingleThreadScheduledExecutor(groupedThreads("onos/openstacknode", "event-handler", log));
Daniel Parkad21c572016-03-09 10:18:24 +0900142
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900143
144 private final DeviceListener deviceListener = new InternalDeviceListener();
145
146 private ApplicationId appId;
147 private ConsistentMap<OpenstackNode, NodeState> nodeStore;
Daniel Parkad21c572016-03-09 10:18:24 +0900148 private NodeId localNodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900149
150 private enum NodeState {
151
152 INIT {
153 @Override
154 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
155 openstackNodeManager.connect(node);
156 }
157 },
158 OVSDB_CONNECTED {
159 @Override
160 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
161 if (!openstackNodeManager.getOvsdbConnectionState(node)) {
162 openstackNodeManager.connect(node);
163 } else {
164 openstackNodeManager.createIntegrationBridge(node);
165 }
166 }
167 },
168 BRIDGE_CREATED {
169 @Override
170 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
171 if (!openstackNodeManager.getOvsdbConnectionState(node)) {
172 openstackNodeManager.connect(node);
173 } else {
174 openstackNodeManager.createTunnelInterface(node);
175 }
176 }
177 },
178 COMPLETE {
179 @Override
180 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
181 openstackNodeManager.postInit(node);
182 }
183 },
184 INCOMPLETE {
185 @Override
186 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
187 }
188 };
189
190 public abstract void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node);
191 }
192
193 @Activate
194 protected void activate() {
195 appId = coreService.registerApplication(OPENSTACK_NODEMANAGER_ID);
Daniel Parkad21c572016-03-09 10:18:24 +0900196 localNodeId = clusterService.getLocalNode().id();
197 leadershipService.runForLeadership(appId.name());
198
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900199 nodeStore = storageService.<OpenstackNode, NodeState>consistentMapBuilder()
200 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
201 .withName(OPENSTACK_NODESTORE)
202 .withApplicationId(appId)
203 .build();
204
205 deviceService.addListener(deviceListener);
206 configRegistry.registerConfigFactory(configFactory);
207 configService.addListener(configListener);
208 readConfiguration();
209
210 log.info("Started");
211 }
212
213 @Deactivate
214 protected void deactivate() {
215 deviceService.removeListener(deviceListener);
216 eventExecutor.shutdown();
217 nodeStore.clear();
218
219 configRegistry.unregisterConfigFactory(configFactory);
220 configService.removeListener(configListener);
Daniel Parkad21c572016-03-09 10:18:24 +0900221 leadershipService.withdraw(appId.name());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900222
223 log.info("Stopped");
224 }
225
226
227 @Override
228 public void addNode(OpenstackNode node) {
229 checkNotNull(node, "Node cannot be null");
230
Daniel Parkad21c572016-03-09 10:18:24 +0900231 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
232 log.debug("Node init requested, localNodeId: {}, leaderNodeId: {}", localNodeId, leaderNodeId);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900233
Daniel Parkad21c572016-03-09 10:18:24 +0900234 //TODO: Fix any node can engage this operation.
235 if (!localNodeId.equals(leaderNodeId)) {
236 log.debug("Only the leaderNode can perform addNode operation");
237 return;
238 }
239 nodeStore.putIfAbsent(node, checkNodeState(node));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900240 NodeState state = checkNodeState(node);
241 state.process(this, node);
242 }
243
244 @Override
245 public void deleteNode(OpenstackNode node) {
246 checkNotNull(node, "Node cannot be null");
247
248 if (getOvsdbConnectionState(node)) {
249 disconnect(node);
250 }
251
252 nodeStore.remove(node);
253 }
254
255 @Override
256 public List<OpenstackNode> getNodes(OpenstackNodeType openstackNodeType) {
257 List<OpenstackNode> nodes = new ArrayList<>();
258 nodes.addAll(nodeStore.keySet().stream().filter(node -> node.openstackNodeType()
259 .equals(openstackNodeType)).collect(Collectors.toList()));
260 return nodes;
261 }
262
263 private List<OpenstackNode> getNodesAll() {
264 List<OpenstackNode> nodes = new ArrayList<>();
265 nodes.addAll(nodeStore.keySet());
266 return nodes;
267 }
268
269 @Override
270 public boolean isComplete(OpenstackNode node) {
271 checkNotNull(node, "Node cannot be null");
272
273 if (!nodeStore.containsKey(node)) {
274 log.warn("Node {} does not exist", node.hostName());
275 return false;
276 } else if (nodeStore.get(node).equals(NodeState.COMPLETE)) {
277 return true;
278 }
279 return false;
280 }
281
282 /**
283 * Checks current state of a given openstack node and returns it.
284 *
285 * @param node openstack node
286 * @return node state
287 */
288 private NodeState checkNodeState(OpenstackNode node) {
289 checkNotNull(node, "Node cannot be null");
290
291 if (checkIntegrationBridge(node) && checkTunnelInterface(node)) {
292 return NodeState.COMPLETE;
293 } else if (checkIntegrationBridge(node)) {
294 return NodeState.BRIDGE_CREATED;
295 } else if (getOvsdbConnectionState(node)) {
296 return NodeState.OVSDB_CONNECTED;
297 } else {
298 return NodeState.INIT;
299 }
300 }
301
302
303 /**
304 * Checks if integration bridge exists and available.
305 *
306 * @param node openstack node
307 * @return true if the bridge is available, false otherwise
308 */
309 private boolean checkIntegrationBridge(OpenstackNode node) {
310 return (deviceService.getDevice(node.intBrId()) != null
311 && deviceService.isAvailable(node.intBrId()));
312 }
313 /**
314 * Checks if tunnel interface exists.
315 *
316 * @param node openstack node
317 * @return true if the interface exists, false otherwise
318 */
319 private boolean checkTunnelInterface(OpenstackNode node) {
320 checkNotNull(node, "Node cannot be null");
321 return deviceService.getPorts(node.intBrId())
322 .stream()
323 .filter(p -> p.annotations().value(PORT_NAME).contains(DEFAULT_TUNNEL) && p.isEnabled())
324 .findAny().isPresent();
325 }
326
327 /**
328 * Returns connection state of OVSDB server for a given node.
329 *
330 * @param node openstack node
331 * @return true if it is connected, false otherwise
332 */
333 private boolean getOvsdbConnectionState(OpenstackNode node) {
334 checkNotNull(node, "Node cannot be null");
335
336 OvsdbClientService ovsdbClient = getOvsdbClient(node);
337 return deviceService.isAvailable(node.ovsdbId()) &&
338 ovsdbClient != null && ovsdbClient.isConnected();
339 }
340
341 /**
342 * Returns OVSDB client for a given node.
343 *
344 * @param node openstack node
345 * @return OVSDB client, or null if it fails to get OVSDB client
346 */
347 private OvsdbClientService getOvsdbClient(OpenstackNode node) {
348 checkNotNull(node, "Node cannot be null");
349
350 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
351 new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt()));
352 if (ovsdbClient == null) {
353 log.debug("Couldn't find OVSDB client for {}", node.hostName());
354 }
355 return ovsdbClient;
356 }
357
358 /**
359 * Connects to OVSDB server for a given node.
360 *
361 * @param node openstack node
362 */
363 private void connect(OpenstackNode node) {
364 checkNotNull(node, "Node cannot be null");
365
366 if (!nodeStore.containsKey(node)) {
367 log.warn("Node {} does not exist", node.hostName());
368 return;
369 }
370
371 if (!getOvsdbConnectionState(node)) {
372 controller.connect(node.ovsdbIp(), node.ovsdbPort());
373 }
374 }
375
376 /**
377 * Creates an integration bridge for a given node.
378 *
379 * @param node openstack node
380 */
381 private void createIntegrationBridge(OpenstackNode node) {
382 if (checkIntegrationBridge(node)) {
383 return;
384 }
385
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700386 List<ControllerInfo> controllers = clusterService.getNodes().stream()
387 .map(controller -> new ControllerInfo(controller.ip(), OFPORT, "tcp"))
388 .collect(Collectors.toList());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900389 String dpid = node.intBrId().toString().substring(DPID_BEGIN);
390
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700391 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
392 .name(DEFAULT_BRIDGE)
393 .failMode(BridgeDescription.FailMode.SECURE)
394 .datapathId(dpid)
395 .disableInBand()
396 .controllers(controllers)
397 .build();
398
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900399 try {
400 DriverHandler handler = driverService.createHandler(node.ovsdbId());
401 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
Hyunsun Moon1251e192016-06-07 16:57:05 -0700402 bridgeConfig.addBridge(bridgeDesc);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900403 } catch (ItemNotFoundException e) {
404 log.warn("Failed to create integration bridge on {}", node.ovsdbId());
405 }
406 }
407
408 /**
409 * Creates tunnel interface to the integration bridge for a given node.
410 *
411 * @param node openstack node
412 */
413 private void createTunnelInterface(OpenstackNode node) {
414 if (checkTunnelInterface(node)) {
415 return;
416 }
417
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700418 TunnelDescription description = DefaultTunnelDescription.builder()
419 .deviceId(DEFAULT_BRIDGE)
420 .ifaceName(DEFAULT_TUNNEL)
421 .type(VXLAN)
422 .remote(TunnelEndPoints.flowTunnelEndpoint())
423 .key(TunnelKeys.flowTunnelKey())
424 .build();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900425 try {
426 DriverHandler handler = driverService.createHandler(node.ovsdbId());
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700427 InterfaceConfig ifaceConfig = handler.behaviour(InterfaceConfig.class);
428 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, description);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900429 } catch (ItemNotFoundException e) {
430 log.warn("Failed to create tunnel interface on {}", node.ovsdbId());
431 }
432 }
433
434 /**
435 * Performs tasks after node initialization.
436 * First disconnect unnecessary OVSDB connection and then installs flow rules
437 * for existing VMs if there are any.
438 *
439 * @param node openstack node
440 */
441 private void postInit(OpenstackNode node) {
442 disconnect(node);
443 log.info("Finished initializing {}", node.hostName());
444 }
445
446 /**
447 * Sets a new state for a given openstack node.
448 *
449 * @param node openstack node
450 * @param newState new node state
451 */
452 private void setNodeState(OpenstackNode node, NodeState newState) {
453 checkNotNull(node, "Node cannot be null");
454
455 log.debug("Changed {} state: {}", node.hostName(), newState.toString());
456
457 nodeStore.put(node, newState);
458 newState.process(this, node);
459 }
460
461 /**
462 * Returns openstack node associated with a given OVSDB device.
463 *
464 * @param ovsdbId OVSDB device id
465 * @return openstack node, null if it fails to find the node
466 */
467 private OpenstackNode getNodeByOvsdbId(DeviceId ovsdbId) {
468
469 return getNodesAll().stream()
470 .filter(node -> node.ovsdbId().equals(ovsdbId))
471 .findFirst().orElse(null);
472 }
473
474 /**
475 * Returns openstack node associated with a given integration bridge.
476 *
477 * @param bridgeId device id of integration bridge
478 * @return openstack node, null if it fails to find the node
479 */
480 private OpenstackNode getNodeByBridgeId(DeviceId bridgeId) {
481 return getNodesAll().stream()
482 .filter(node -> node.intBrId().equals(bridgeId))
483 .findFirst().orElse(null);
484 }
485 /**
486 * Disconnects OVSDB server for a given node.
487 *
488 * @param node openstack node
489 */
490 private void disconnect(OpenstackNode node) {
491 checkNotNull(node, "Node cannot be null");
492
493 if (!nodeStore.containsKey(node)) {
494 log.warn("Node {} does not exist", node.hostName());
495 return;
496 }
497
498 if (getOvsdbConnectionState(node)) {
499 OvsdbClientService ovsdbClient = getOvsdbClient(node);
500 ovsdbClient.disconnect();
501 }
502 }
503
504 private class InternalDeviceListener implements DeviceListener {
505
506 @Override
507 public void event(DeviceEvent event) {
Daniel Parkad21c572016-03-09 10:18:24 +0900508 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
509
510 //TODO: Fix any node can engage this operation.
511 if (!localNodeId.equals(leaderNodeId)) {
512 log.debug("Only the leaderNode can process events");
513 return;
514 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900515
516 Device device = event.subject();
517 ConnectionHandler<Device> handler =
518 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
519
520 switch (event.type()) {
521 case PORT_ADDED:
522 eventExecutor.submit(() -> bridgeHandler.portAdded(event.port()));
523 break;
524 case PORT_UPDATED:
525 if (!event.port().isEnabled()) {
526 eventExecutor.submit(() -> bridgeHandler.portRemoved(event.port()));
527 }
528 break;
529 case DEVICE_ADDED:
530 case DEVICE_AVAILABILITY_CHANGED:
531 if (deviceService.isAvailable(device.id())) {
532 eventExecutor.submit(() -> handler.connected(device));
533 } else {
534 eventExecutor.submit(() -> handler.disconnected(device));
535 }
536 break;
537 default:
538 log.debug("Unsupported event type {}", event.type().toString());
539 break;
540 }
541 }
542 }
543
544 private class OvsdbHandler implements ConnectionHandler<Device> {
545
546 @Override
547 public void connected(Device device) {
548 OpenstackNode node = getNodeByOvsdbId(device.id());
549 if (node != null) {
550 setNodeState(node, checkNodeState(node));
551 }
552 }
553
554 @Override
555 public void disconnected(Device device) {
556 if (!deviceService.isAvailable(device.id())) {
557 adminService.removeDevice(device.id());
558 }
559 }
560 }
561
562 private class BridgeHandler implements ConnectionHandler<Device> {
563
564 @Override
565 public void connected(Device device) {
566 OpenstackNode node = getNodeByBridgeId(device.id());
567 if (node != null) {
568 setNodeState(node, checkNodeState(node));
569 }
570 }
571
572 @Override
573 public void disconnected(Device device) {
574 OpenstackNode node = getNodeByBridgeId(device.id());
575 if (node != null) {
576 log.debug("Integration Bridge is disconnected from {}", node.hostName());
577 setNodeState(node, NodeState.INCOMPLETE);
578 }
579 }
580
581 /**
582 * Handles port added situation.
583 * If the added port is tunnel port, proceed remaining node initialization.
584 * Otherwise, do nothing.
585 *
586 * @param port port
587 */
588 public void portAdded(Port port) {
589 if (!port.annotations().value(PORT_NAME).contains(DEFAULT_TUNNEL)) {
590 return;
591 }
592
593 OpenstackNode node = getNodeByBridgeId((DeviceId) port.element().id());
594 if (node != null) {
595 setNodeState(node, checkNodeState(node));
596 }
597 }
598
599 /**
600 * Handles port removed situation.
601 * If the removed port is tunnel port, proceed remaining node initialization.
602 * Others, do nothing.
603 *
604 * @param port port
605 */
606 public void portRemoved(Port port) {
607 if (!port.annotations().value(PORT_NAME).contains(DEFAULT_TUNNEL)) {
608 return;
609 }
610
611 OpenstackNode node = getNodeByBridgeId((DeviceId) port.element().id());
612 if (node != null) {
613 log.info("Tunnel interface is removed from {}", node.hostName());
614 setNodeState(node, NodeState.INCOMPLETE);
615 }
616 }
617 }
618
619
620 private void readConfiguration() {
621 OpenstackNodeConfig config =
622 configService.getConfig(appId, OpenstackNodeConfig.class);
623
624 if (config == null) {
625 log.error("No configuration found");
626 return;
627 }
628
629 config.openstackNodes().stream().forEach(node -> addNode(node));
630 log.info("Node configured");
631 }
632
633 private class InternalConfigListener implements NetworkConfigListener {
634
635 @Override
636 public void event(NetworkConfigEvent event) {
637 if (!event.configClass().equals(OpenstackNodeConfig.class)) {
638 return;
639 }
640
641 switch (event.type()) {
642 case CONFIG_ADDED:
643 case CONFIG_UPDATED:
644 eventExecutor.execute(OpenstackNodeManager.this::readConfiguration);
645 break;
646 default:
647 break;
648 }
649 }
650 }
651
652
653}
654