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