blob: 165e665c00d53ad96d5466f9ce2e336b77b160ad [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;
38import org.onosproject.net.behaviour.BridgeName;
39import org.onosproject.net.behaviour.ControllerInfo;
40import org.onosproject.net.behaviour.DefaultTunnelDescription;
41import org.onosproject.net.behaviour.TunnelConfig;
42import org.onosproject.net.behaviour.TunnelDescription;
43import org.onosproject.net.behaviour.TunnelName;
44import org.onosproject.net.config.ConfigFactory;
45import org.onosproject.net.config.NetworkConfigEvent;
46import org.onosproject.net.config.NetworkConfigListener;
47import org.onosproject.net.config.NetworkConfigRegistry;
48import org.onosproject.net.config.NetworkConfigService;
49import org.onosproject.net.config.basics.SubjectFactories;
50import org.onosproject.net.device.DeviceAdminService;
51import org.onosproject.net.device.DeviceEvent;
52import org.onosproject.net.device.DeviceListener;
53import org.onosproject.net.device.DeviceService;
54import org.onosproject.net.driver.DriverHandler;
55import org.onosproject.net.driver.DriverService;
56import org.onosproject.ovsdb.controller.OvsdbClientService;
57import org.onosproject.ovsdb.controller.OvsdbController;
58import org.onosproject.ovsdb.controller.OvsdbNodeId;
59import org.onosproject.store.serializers.KryoNamespaces;
60import org.onosproject.store.service.ConsistentMap;
61import org.onosproject.store.service.Serializer;
62import org.onosproject.store.service.StorageService;
63import org.slf4j.Logger;
64
Daniel Parkad21c572016-03-09 10:18:24 +090065import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090066import static org.onlab.util.Tools.groupedThreads;
67import static org.onosproject.net.Device.Type.SWITCH;
68import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
69import static org.slf4j.LoggerFactory.getLogger;
70
71import java.util.ArrayList;
72import java.util.List;
73import java.util.Map;
74import java.util.concurrent.ExecutorService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090075import java.util.stream.Collectors;
76
77import static com.google.common.base.Preconditions.checkNotNull;
78
79
80/**
81 * Initializes devices in compute/gateway nodes according to there type.
82 */
83@Component(immediate = true)
84@Service
85public class OpenstackNodeManager implements OpenstackNodeService {
86 protected final Logger log = getLogger(getClass());
Daniel Parka7d6e9f2016-01-18 17:54:14 +090087 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
88 .register(KryoNamespaces.API)
89 .register(OpenstackNode.class)
90 .register(OpenstackNodeType.class)
91 .register(NodeState.class);
92 private static final String DEFAULT_BRIDGE = "br-int";
93 private static final String DEFAULT_TUNNEL = "vxlan";
94 private static final String PORT_NAME = "portName";
95 private static final String OPENSTACK_NODESTORE = "openstacknode-nodestore";
96 private static final String OPENSTACK_NODEMANAGER_ID = "org.onosproject.openstacknode";
97
98 private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS
99 = ImmutableMap.of("key", "flow", "remote_ip", "flow");
100
101 private static final int DPID_BEGIN = 3;
102 private static final int OFPORT = 6653;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected CoreService coreService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected DeviceService deviceService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected OvsdbController controller;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected ClusterService clusterService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected DriverService driverService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected DeviceAdminService adminService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected StorageService storageService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected NetworkConfigService configService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected NetworkConfigRegistry configRegistry;
130
Daniel Parkad21c572016-03-09 10:18:24 +0900131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected LeadershipService leadershipService;
133
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900134 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
135 private final BridgeHandler bridgeHandler = new BridgeHandler();
136 private final NetworkConfigListener configListener = new InternalConfigListener();
137 private final ConfigFactory configFactory =
138 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, OpenstackNodeConfig.class, "openstacknode") {
139 @Override
140 public OpenstackNodeConfig createConfig() {
141 return new OpenstackNodeConfig();
142 }
143 };
144
Daniel Parkad21c572016-03-09 10:18:24 +0900145 private final ExecutorService eventExecutor =
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700146 newSingleThreadScheduledExecutor(groupedThreads("onos/openstacknode", "event-handler", log));
Daniel Parkad21c572016-03-09 10:18:24 +0900147
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900148
149 private final DeviceListener deviceListener = new InternalDeviceListener();
150
151 private ApplicationId appId;
152 private ConsistentMap<OpenstackNode, NodeState> nodeStore;
Daniel Parkad21c572016-03-09 10:18:24 +0900153 private NodeId localNodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900154
155 private enum NodeState {
156
157 INIT {
158 @Override
159 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
160 openstackNodeManager.connect(node);
161 }
162 },
163 OVSDB_CONNECTED {
164 @Override
165 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
166 if (!openstackNodeManager.getOvsdbConnectionState(node)) {
167 openstackNodeManager.connect(node);
168 } else {
169 openstackNodeManager.createIntegrationBridge(node);
170 }
171 }
172 },
173 BRIDGE_CREATED {
174 @Override
175 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
176 if (!openstackNodeManager.getOvsdbConnectionState(node)) {
177 openstackNodeManager.connect(node);
178 } else {
179 openstackNodeManager.createTunnelInterface(node);
180 }
181 }
182 },
183 COMPLETE {
184 @Override
185 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
186 openstackNodeManager.postInit(node);
187 }
188 },
189 INCOMPLETE {
190 @Override
191 public void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node) {
192 }
193 };
194
195 public abstract void process(OpenstackNodeManager openstackNodeManager, OpenstackNode node);
196 }
197
198 @Activate
199 protected void activate() {
200 appId = coreService.registerApplication(OPENSTACK_NODEMANAGER_ID);
Daniel Parkad21c572016-03-09 10:18:24 +0900201 localNodeId = clusterService.getLocalNode().id();
202 leadershipService.runForLeadership(appId.name());
203
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900204 nodeStore = storageService.<OpenstackNode, NodeState>consistentMapBuilder()
205 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
206 .withName(OPENSTACK_NODESTORE)
207 .withApplicationId(appId)
208 .build();
209
210 deviceService.addListener(deviceListener);
211 configRegistry.registerConfigFactory(configFactory);
212 configService.addListener(configListener);
213 readConfiguration();
214
215 log.info("Started");
216 }
217
218 @Deactivate
219 protected void deactivate() {
220 deviceService.removeListener(deviceListener);
221 eventExecutor.shutdown();
222 nodeStore.clear();
223
224 configRegistry.unregisterConfigFactory(configFactory);
225 configService.removeListener(configListener);
Daniel Parkad21c572016-03-09 10:18:24 +0900226 leadershipService.withdraw(appId.name());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900227
228 log.info("Stopped");
229 }
230
231
232 @Override
233 public void addNode(OpenstackNode node) {
234 checkNotNull(node, "Node cannot be null");
235
Daniel Parkad21c572016-03-09 10:18:24 +0900236 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
237 log.debug("Node init requested, localNodeId: {}, leaderNodeId: {}", localNodeId, leaderNodeId);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900238
Daniel Parkad21c572016-03-09 10:18:24 +0900239 //TODO: Fix any node can engage this operation.
240 if (!localNodeId.equals(leaderNodeId)) {
241 log.debug("Only the leaderNode can perform addNode operation");
242 return;
243 }
244 nodeStore.putIfAbsent(node, checkNodeState(node));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900245 NodeState state = checkNodeState(node);
246 state.process(this, node);
247 }
248
249 @Override
250 public void deleteNode(OpenstackNode node) {
251 checkNotNull(node, "Node cannot be null");
252
253 if (getOvsdbConnectionState(node)) {
254 disconnect(node);
255 }
256
257 nodeStore.remove(node);
258 }
259
260 @Override
261 public List<OpenstackNode> getNodes(OpenstackNodeType openstackNodeType) {
262 List<OpenstackNode> nodes = new ArrayList<>();
263 nodes.addAll(nodeStore.keySet().stream().filter(node -> node.openstackNodeType()
264 .equals(openstackNodeType)).collect(Collectors.toList()));
265 return nodes;
266 }
267
268 private List<OpenstackNode> getNodesAll() {
269 List<OpenstackNode> nodes = new ArrayList<>();
270 nodes.addAll(nodeStore.keySet());
271 return nodes;
272 }
273
274 @Override
275 public boolean isComplete(OpenstackNode node) {
276 checkNotNull(node, "Node cannot be null");
277
278 if (!nodeStore.containsKey(node)) {
279 log.warn("Node {} does not exist", node.hostName());
280 return false;
281 } else if (nodeStore.get(node).equals(NodeState.COMPLETE)) {
282 return true;
283 }
284 return false;
285 }
286
287 /**
288 * Checks current state of a given openstack node and returns it.
289 *
290 * @param node openstack node
291 * @return node state
292 */
293 private NodeState checkNodeState(OpenstackNode node) {
294 checkNotNull(node, "Node cannot be null");
295
296 if (checkIntegrationBridge(node) && checkTunnelInterface(node)) {
297 return NodeState.COMPLETE;
298 } else if (checkIntegrationBridge(node)) {
299 return NodeState.BRIDGE_CREATED;
300 } else if (getOvsdbConnectionState(node)) {
301 return NodeState.OVSDB_CONNECTED;
302 } else {
303 return NodeState.INIT;
304 }
305 }
306
307
308 /**
309 * Checks if integration bridge exists and available.
310 *
311 * @param node openstack node
312 * @return true if the bridge is available, false otherwise
313 */
314 private boolean checkIntegrationBridge(OpenstackNode node) {
315 return (deviceService.getDevice(node.intBrId()) != null
316 && deviceService.isAvailable(node.intBrId()));
317 }
318 /**
319 * Checks if tunnel interface exists.
320 *
321 * @param node openstack node
322 * @return true if the interface exists, false otherwise
323 */
324 private boolean checkTunnelInterface(OpenstackNode node) {
325 checkNotNull(node, "Node cannot be null");
326 return deviceService.getPorts(node.intBrId())
327 .stream()
328 .filter(p -> p.annotations().value(PORT_NAME).contains(DEFAULT_TUNNEL) && p.isEnabled())
329 .findAny().isPresent();
330 }
331
332 /**
333 * Returns connection state of OVSDB server for a given node.
334 *
335 * @param node openstack node
336 * @return true if it is connected, false otherwise
337 */
338 private boolean getOvsdbConnectionState(OpenstackNode node) {
339 checkNotNull(node, "Node cannot be null");
340
341 OvsdbClientService ovsdbClient = getOvsdbClient(node);
342 return deviceService.isAvailable(node.ovsdbId()) &&
343 ovsdbClient != null && ovsdbClient.isConnected();
344 }
345
346 /**
347 * Returns OVSDB client for a given node.
348 *
349 * @param node openstack node
350 * @return OVSDB client, or null if it fails to get OVSDB client
351 */
352 private OvsdbClientService getOvsdbClient(OpenstackNode node) {
353 checkNotNull(node, "Node cannot be null");
354
355 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
356 new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt()));
357 if (ovsdbClient == null) {
358 log.debug("Couldn't find OVSDB client for {}", node.hostName());
359 }
360 return ovsdbClient;
361 }
362
363 /**
364 * Connects to OVSDB server for a given node.
365 *
366 * @param node openstack node
367 */
368 private void connect(OpenstackNode node) {
369 checkNotNull(node, "Node cannot be null");
370
371 if (!nodeStore.containsKey(node)) {
372 log.warn("Node {} does not exist", node.hostName());
373 return;
374 }
375
376 if (!getOvsdbConnectionState(node)) {
377 controller.connect(node.ovsdbIp(), node.ovsdbPort());
378 }
379 }
380
381 /**
382 * Creates an integration bridge for a given node.
383 *
384 * @param node openstack node
385 */
386 private void createIntegrationBridge(OpenstackNode node) {
387 if (checkIntegrationBridge(node)) {
388 return;
389 }
390
391 List<ControllerInfo> controllers = new ArrayList<>();
392 Sets.newHashSet(clusterService.getNodes()).stream()
393 .forEach(controller -> {
394 ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
395 controllers.add(ctrlInfo);
396 });
397 String dpid = node.intBrId().toString().substring(DPID_BEGIN);
398
399 try {
400 DriverHandler handler = driverService.createHandler(node.ovsdbId());
401 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
402 bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE), dpid, controllers);
403 } 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
418 DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder();
419 for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
420 optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
421 }
422 TunnelDescription description =
423 new DefaultTunnelDescription(null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL),
424 optionBuilder.build());
425 try {
426 DriverHandler handler = driverService.createHandler(node.ovsdbId());
427 TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class);
428 tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE), description);
429 } 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