blob: 397ff372a701e423156b7a7a2bba102e19f52eb2 [file] [log] [blame]
Hyunsun Moon0d457362017-06-27 17:19:41 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon0d457362017-06-27 17:19:41 +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.impl;
17
Hyunsun Moon0d457362017-06-27 17:19:41 +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.Modified;
22import org.apache.felix.scr.annotations.Property;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.packet.IpAddress;
26import org.onlab.util.Tools;
27import org.onosproject.cfg.ComponentConfigService;
28import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.ControllerNode;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090034import org.onosproject.net.Device;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.Port;
37import org.onosproject.net.behaviour.BridgeConfig;
38import org.onosproject.net.behaviour.BridgeDescription;
39import org.onosproject.net.behaviour.BridgeName;
40import org.onosproject.net.behaviour.ControllerInfo;
41import org.onosproject.net.behaviour.DefaultBridgeDescription;
Hyunsun Moon0d457362017-06-27 17:19:41 +090042import org.onosproject.net.behaviour.DefaultTunnelDescription;
43import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
44import org.onosproject.net.behaviour.InterfaceConfig;
Hyunsun Moon0d457362017-06-27 17:19:41 +090045import org.onosproject.net.behaviour.TunnelDescription;
46import org.onosproject.net.behaviour.TunnelEndPoints;
47import org.onosproject.net.behaviour.TunnelKeys;
48import org.onosproject.net.device.DeviceAdminService;
49import org.onosproject.net.device.DeviceEvent;
50import org.onosproject.net.device.DeviceListener;
51import org.onosproject.net.device.DeviceService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090052import org.onosproject.net.flow.instructions.ExtensionPropertyException;
53import org.onosproject.net.flow.instructions.ExtensionTreatment;
daniel parkb18424c2018-02-05 15:43:43 +090054
Hyunsun Moon0d457362017-06-27 17:19:41 +090055import org.onosproject.openstacknode.api.NodeState;
56import org.onosproject.openstacknode.api.OpenstackNode;
Hyunsun Moon0d457362017-06-27 17:19:41 +090057import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
58import org.onosproject.openstacknode.api.OpenstackNodeEvent;
59import org.onosproject.openstacknode.api.OpenstackNodeHandler;
60import org.onosproject.openstacknode.api.OpenstackNodeListener;
61import org.onosproject.openstacknode.api.OpenstackNodeService;
62import org.onosproject.ovsdb.controller.OvsdbClientService;
63import org.onosproject.ovsdb.controller.OvsdbController;
64import org.onosproject.ovsdb.controller.OvsdbNodeId;
65import org.osgi.service.component.ComponentContext;
66import org.slf4j.Logger;
67
68import java.util.Dictionary;
69import java.util.List;
70import java.util.Objects;
71import java.util.Set;
72import java.util.concurrent.ExecutorService;
73import java.util.stream.Collectors;
74
Hyunsun Moon0d457362017-06-27 17:19:41 +090075import static java.util.concurrent.Executors.newSingleThreadExecutor;
76import static org.onlab.packet.TpPort.tpPort;
77import static org.onlab.util.Tools.groupedThreads;
78import static org.onosproject.net.AnnotationKeys.PORT_NAME;
79import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Hyunsun Moon0d457362017-06-27 17:19:41 +090080import static org.onosproject.openstacknode.api.Constants.*;
Hyunsun Moon0d457362017-06-27 17:19:41 +090081import static org.onosproject.openstacknode.api.NodeState.*;
Hyunsun Moon0d457362017-06-27 17:19:41 +090082import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
83import static org.onosproject.openstacknode.api.OpenstackNodeService.APP_ID;
84import static org.slf4j.LoggerFactory.getLogger;
85
86/**
87 * Service bootstraps openstack node based on its type.
88 */
89@Component(immediate = true)
90public class DefaultOpenstackNodeHandler implements OpenstackNodeHandler {
91
92 protected final Logger log = getLogger(getClass());
93
94 private static final String OVSDB_PORT = "ovsdbPortNum";
95 private static final int DEFAULT_OVSDB_PORT = 6640;
96 private static final String DEFAULT_OF_PROTO = "tcp";
97 private static final int DEFAULT_OFPORT = 6653;
98 private static final int DPID_BEGIN = 3;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected CoreService coreService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected LeadershipService leadershipService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected ClusterService clusterService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected DeviceService deviceService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected DeviceAdminService deviceAdminService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected OvsdbController ovsdbController;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900119 protected OpenstackNodeService osNodeService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected OpenstackNodeAdminService osNodeAdminService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected ComponentConfigService componentConfigService;
126
127 @Property(name = OVSDB_PORT, intValue = DEFAULT_OVSDB_PORT,
128 label = "OVSDB server listen port")
129 private int ovsdbPort = DEFAULT_OVSDB_PORT;
130
131 private final ExecutorService eventExecutor = newSingleThreadExecutor(
132 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
133
134 private final DeviceListener ovsdbListener = new InternalOvsdbListener();
135 private final DeviceListener bridgeListener = new InternalBridgeListener();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900136 private final OpenstackNodeListener osNodeListener = new InternalOpenstackNodeListener();
137
138 private ApplicationId appId;
139 private NodeId localNode;
140
141 @Activate
142 protected void activate() {
143 appId = coreService.getAppId(APP_ID);
144 localNode = clusterService.getLocalNode().id();
145
146 componentConfigService.registerProperties(getClass());
147 leadershipService.runForLeadership(appId.name());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900148 deviceService.addListener(ovsdbListener);
149 deviceService.addListener(bridgeListener);
150 osNodeService.addListener(osNodeListener);
151
152 log.info("Started");
153 }
154
155 @Deactivate
156 protected void deactivate() {
157 osNodeService.removeListener(osNodeListener);
158 deviceService.removeListener(bridgeListener);
159 deviceService.removeListener(ovsdbListener);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900160 componentConfigService.unregisterProperties(getClass(), false);
161 leadershipService.withdraw(appId.name());
162 eventExecutor.shutdown();
163
164 log.info("Stopped");
165 }
166
167 @Modified
168 protected void modified(ComponentContext context) {
169 Dictionary<?, ?> properties = context.getProperties();
170 int updatedOvsdbPort = Tools.getIntegerProperty(properties, OVSDB_PORT);
171 if (!Objects.equals(updatedOvsdbPort, ovsdbPort)) {
172 ovsdbPort = updatedOvsdbPort;
173 }
174
175 log.info("Modified");
176 }
177
178 @Override
179 public void processInitState(OpenstackNode osNode) {
180 if (!isOvsdbConnected(osNode)) {
181 ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPort));
182 return;
183 }
184 if (!deviceService.isAvailable(osNode.intgBridge())) {
185 createBridge(osNode, INTEGRATION_BRIDGE, osNode.intgBridge());
186 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900187 }
188
189 @Override
190 public void processDeviceCreatedState(OpenstackNode osNode) {
daniel parkb18424c2018-02-05 15:43:43 +0900191 try {
192 if (!isOvsdbConnected(osNode)) {
193 ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPort));
194 return;
195 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900196
daniel parkb18424c2018-02-05 15:43:43 +0900197 if (osNode.type() == GATEWAY) {
198 addSystemInterface(osNode, INTEGRATION_BRIDGE, osNode.uplinkPort());
199 }
200
201 if (osNode.dataIp() != null &&
202 !isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
203 createTunnelInterface(osNode);
204 }
205
206 if (osNode.vlanIntf() != null &&
207 !isIntfEnabled(osNode, osNode.vlanIntf())) {
208 addSystemInterface(osNode, INTEGRATION_BRIDGE, osNode.vlanIntf());
209 }
210 } catch (Exception e) {
Jian Li340165f2018-02-27 10:38:17 +0900211 log.error("Exception occurred because of {}", e.toString());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900212 }
213 }
214
215 @Override
216 public void processCompleteState(OpenstackNode osNode) {
217 OvsdbClientService ovsdbClient = ovsdbController.getOvsdbClient(
218 new OvsdbNodeId(osNode.managementIp(), DEFAULT_OVSDB_PORT));
219 if (ovsdbClient != null && ovsdbClient.isConnected()) {
220 ovsdbClient.disconnect();
221 }
222 }
223
224 @Override
225 public void processIncompleteState(OpenstackNode osNode) {
daniel parkb18424c2018-02-05 15:43:43 +0900226 //TODO
Hyunsun Moon0d457362017-06-27 17:19:41 +0900227 }
228
Jian Li340165f2018-02-27 10:38:17 +0900229 /**
230 * Checks whether the controller has a connection with an OVSDB that resides
231 * inside the given openstack node.
232 *
233 * @param osNode openstack node
234 * @return true if the controller is connected to the OVSDB, false otherwise
235 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900236 private boolean isOvsdbConnected(OpenstackNode osNode) {
237 OvsdbNodeId ovsdb = new OvsdbNodeId(osNode.managementIp(), ovsdbPort);
238 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
239 return deviceService.isAvailable(osNode.ovsdb()) &&
240 client != null &&
241 client.isConnected();
242 }
243
Jian Li340165f2018-02-27 10:38:17 +0900244 /**
245 * Creates a bridge with a given name on a given openstack node.
246 *
247 * @param osNode openstack node
248 * @param bridgeName bridge name
249 * @param deviceId device identifier
250 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900251 private void createBridge(OpenstackNode osNode, String bridgeName, DeviceId deviceId) {
252 Device device = deviceService.getDevice(osNode.ovsdb());
253 if (device == null || !device.is(BridgeConfig.class)) {
254 log.error("Failed to create integration bridge on {}", osNode.ovsdb());
255 return;
256 }
257
daniel parkb18424c2018-02-05 15:43:43 +0900258 Set<IpAddress> controllerIps = clusterService.getNodes().stream()
Hyunsun Moon0d457362017-06-27 17:19:41 +0900259 .map(ControllerNode::ip)
260 .collect(Collectors.toSet());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900261
262 List<ControllerInfo> controllers = controllerIps.stream()
263 .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
264 .collect(Collectors.toList());
265
266 String dpid = deviceId.toString().substring(DPID_BEGIN);
daniel parkb18424c2018-02-05 15:43:43 +0900267
Hyunsun Moon0d457362017-06-27 17:19:41 +0900268 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
269 .name(bridgeName)
270 .failMode(BridgeDescription.FailMode.SECURE)
271 .datapathId(dpid)
272 .disableInBand()
273 .controllers(controllers)
274 .build();
275
276 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
277 bridgeConfig.addBridge(bridgeDesc);
278 }
279
Jian Li340165f2018-02-27 10:38:17 +0900280 /**
281 * Adds a network interface (aka port) into a given bridge of openstack node.
282 *
283 * @param osNode openstack node
284 * @param bridgeName bridge name
285 * @param intfName interface name
286 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900287 private void addSystemInterface(OpenstackNode osNode, String bridgeName, String intfName) {
288 Device device = deviceService.getDevice(osNode.ovsdb());
289 if (device == null || !device.is(BridgeConfig.class)) {
290 return;
291 }
292 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
293 bridgeConfig.addPort(BridgeName.bridgeName(bridgeName), intfName);
294 }
295
Jian Li340165f2018-02-27 10:38:17 +0900296 /**
297 * Creates a tunnel interface in a given openstack node.
298 *
299 * @param osNode openstack node
300 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900301 private void createTunnelInterface(OpenstackNode osNode) {
302 if (isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
303 return;
304 }
305
306 Device device = deviceService.getDevice(osNode.ovsdb());
307 if (device == null || !device.is(InterfaceConfig.class)) {
308 log.error("Failed to create tunnel interface on {}", osNode.ovsdb());
309 return;
310 }
311
312 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
313 .deviceId(INTEGRATION_BRIDGE)
314 .ifaceName(DEFAULT_TUNNEL)
315 .type(TunnelDescription.Type.VXLAN)
316 .remote(TunnelEndPoints.flowTunnelEndpoint())
317 .key(TunnelKeys.flowTunnelKey())
318 .build();
319
320 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
321 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
322 }
323
Hyunsun Moon0d457362017-06-27 17:19:41 +0900324 private ExtensionTreatment tunnelDstTreatment(DeviceId deviceId, IpAddress remoteIp) {
325 Device device = deviceService.getDevice(deviceId);
326 if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
327 log.error("The extension treatment is not supported");
328 return null;
329 }
330
Ray Milkey74e59132018-01-17 15:24:52 -0800331 if (device == null) {
332 return null;
333 }
334
Hyunsun Moon0d457362017-06-27 17:19:41 +0900335 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
336 ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
337 try {
338 treatment.setPropertyValue("tunnelDst", remoteIp.getIp4Address());
339 return treatment;
340 } catch (ExtensionPropertyException e) {
341 log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
342 return null;
343 }
344 }
345
Jian Li340165f2018-02-27 10:38:17 +0900346 /**
347 * Checks whether a given network interface in a given openstack node is enabled or not.
348 *
349 * @param osNode openstack node
350 * @param intf network interface name
351 * @return true if the given interface is enabled, false otherwise
352 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900353 private boolean isIntfEnabled(OpenstackNode osNode, String intf) {
354 if (!deviceService.isAvailable(osNode.intgBridge())) {
355 return false;
356 }
357 return deviceService.getPorts(osNode.intgBridge()).stream()
358 .anyMatch(port -> Objects.equals(
359 port.annotations().value(PORT_NAME), intf) &&
360 port.isEnabled());
361 }
362
Jian Li340165f2018-02-27 10:38:17 +0900363 /**
364 * Checks whether all requirements for this state are fulfilled or not.
365 *
366 * @param osNode openstack node
367 * @return true if all requirements are fulfilled, false otherwise
368 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900369 private boolean isCurrentStateDone(OpenstackNode osNode) {
370 switch (osNode.state()) {
371 case INIT:
372 if (!deviceService.isAvailable(osNode.intgBridge())) {
373 return false;
374 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900375 return true;
376 case DEVICE_CREATED:
377 if (osNode.dataIp() != null &&
378 !isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
379 return false;
380 }
381 if (osNode.vlanIntf() != null &&
382 !isIntfEnabled(osNode, osNode.vlanIntf())) {
383 return false;
384 }
daniel parkb18424c2018-02-05 15:43:43 +0900385 if (osNode.type() == GATEWAY &&
386 !isIntfEnabled(osNode, osNode.uplinkPort())) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900387 return false;
388 }
389 return true;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900390 case COMPLETE:
391 return false;
392 case INCOMPLETE:
393 // always return false
394 // run init CLI to re-trigger node bootstrap
395 return false;
396 default:
397 return true;
398 }
399 }
400
Jian Li340165f2018-02-27 10:38:17 +0900401 /**
402 * Configures the openstack node with new state.
403 *
404 * @param osNode openstack node
405 * @param newState a new state
406 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900407 private void setState(OpenstackNode osNode, NodeState newState) {
408 if (osNode.state() == newState) {
409 return;
410 }
411 OpenstackNode updated = osNode.updateState(newState);
412 osNodeAdminService.updateNode(updated);
413 log.info("Changed {} state: {}", osNode.hostname(), newState);
414 }
415
Jian Li340165f2018-02-27 10:38:17 +0900416 /**
417 * Bootstraps a new openstack node.
418 *
419 * @param osNode openstack node
420 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900421 private void bootstrapNode(OpenstackNode osNode) {
422 if (isCurrentStateDone(osNode)) {
423 setState(osNode, osNode.state().nextState());
424 } else {
425 log.trace("Processing {} state for {}", osNode.state(), osNode.hostname());
426 osNode.state().process(this, osNode);
427 }
428 }
429
Jian Li340165f2018-02-27 10:38:17 +0900430 /**
431 * An internal OVSDB listener. This listener is used for listening the
432 * network facing events from OVSDB device. If a new OVSDB device is detected,
433 * ONOS tries to bootstrap the openstack node.
434 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900435 private class InternalOvsdbListener implements DeviceListener {
436
437 @Override
438 public boolean isRelevant(DeviceEvent event) {
439 NodeId leader = leadershipService.getLeader(appId.name());
440 return Objects.equals(localNode, leader) &&
441 event.subject().type() == Device.Type.CONTROLLER &&
442 osNodeService.node(event.subject().id()) != null;
443 }
444
445 @Override
446 public void event(DeviceEvent event) {
447 Device device = event.subject();
448 OpenstackNode osNode = osNodeService.node(device.id());
449
450 switch (event.type()) {
451 case DEVICE_AVAILABILITY_CHANGED:
452 case DEVICE_ADDED:
453 eventExecutor.execute(() -> {
454 if (deviceService.isAvailable(device.id())) {
455 log.debug("OVSDB {} detected", device.id());
456 bootstrapNode(osNode);
457 } else if (osNode.state() == COMPLETE) {
458 log.debug("Removing OVSDB {}", device.id());
459 deviceAdminService.removeDevice(device.id());
460 }
461 });
462 break;
463 case PORT_ADDED:
464 case PORT_REMOVED:
465 case DEVICE_REMOVED:
466 default:
467 // do nothing
468 break;
469 }
470 }
471 }
472
Jian Li340165f2018-02-27 10:38:17 +0900473 /**
474 * An internal integration bridge listener. This listener is used for
475 * listening the events from integration bridge. To listen the events from
476 * other types of bridge such as provider bridge or tunnel bridge, we need
477 * to augment OpenstackNodeService.node() method.
478 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900479 private class InternalBridgeListener implements DeviceListener {
480
481 @Override
482 public boolean isRelevant(DeviceEvent event) {
483 NodeId leader = leadershipService.getLeader(appId.name());
484 return Objects.equals(localNode, leader) &&
485 event.subject().type() == Device.Type.SWITCH &&
486 osNodeService.node(event.subject().id()) != null;
487 }
488
489 @Override
490 public void event(DeviceEvent event) {
491 Device device = event.subject();
492 OpenstackNode osNode = osNodeService.node(device.id());
493
494 switch (event.type()) {
495 case DEVICE_AVAILABILITY_CHANGED:
496 case DEVICE_ADDED:
497 eventExecutor.execute(() -> {
498 if (deviceService.isAvailable(device.id())) {
499 log.debug("Integration bridge created on {}", osNode.hostname());
500 bootstrapNode(osNode);
501 } else if (osNode.state() == COMPLETE) {
502 log.warn("Device {} disconnected", device.id());
503 setState(osNode, INCOMPLETE);
504 }
505 });
506 break;
507 case PORT_ADDED:
508 eventExecutor.execute(() -> {
509 Port port = event.port();
510 String portName = port.annotations().value(PORT_NAME);
511 if (osNode.state() == DEVICE_CREATED && (
512 Objects.equals(portName, DEFAULT_TUNNEL) ||
513 Objects.equals(portName, osNode.vlanIntf()) ||
daniel parkb18424c2018-02-05 15:43:43 +0900514 Objects.equals(portName, osNode.uplinkPort()))) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900515 log.debug("Interface {} added to {}", portName, event.subject().id());
516 bootstrapNode(osNode);
517 }
518 });
519 break;
520 case PORT_REMOVED:
521 eventExecutor.execute(() -> {
522 Port port = event.port();
523 String portName = port.annotations().value(PORT_NAME);
524 if (osNode.state() == COMPLETE && (
525 Objects.equals(portName, DEFAULT_TUNNEL) ||
526 Objects.equals(portName, osNode.vlanIntf()) ||
daniel parkb18424c2018-02-05 15:43:43 +0900527 Objects.equals(portName, osNode.uplinkPort()))) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900528 log.warn("Interface {} removed from {}", portName, event.subject().id());
529 setState(osNode, INCOMPLETE);
530 }
531 });
532 break;
533 case PORT_UPDATED:
534 case DEVICE_REMOVED:
535 default:
536 // do nothing
537 break;
538 }
539 }
540 }
541
Jian Li340165f2018-02-27 10:38:17 +0900542 /**
543 * An internal openstack node listener.
544 * The notification is triggered by OpenstackNodeStore.
545 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900546 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
547
548 @Override
549 public boolean isRelevant(OpenstackNodeEvent event) {
550 NodeId leader = leadershipService.getLeader(appId.name());
551 return Objects.equals(localNode, leader);
552 }
553
554 @Override
555 public void event(OpenstackNodeEvent event) {
556 switch (event.type()) {
557 case OPENSTACK_NODE_CREATED:
558 case OPENSTACK_NODE_UPDATED:
559 eventExecutor.execute(() -> {
560 bootstrapNode(event.subject());
561 });
562 break;
563 case OPENSTACK_NODE_COMPLETE:
564 break;
565 case OPENSTACK_NODE_REMOVED:
566 break;
567 default:
568 break;
569 }
570 }
571 }
572}