blob: bea3a41b5a2eaf35f2e2a58320f1b470387cd18f [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 parke49eb382017-04-05 16:48:28 +090018import com.google.common.collect.ImmutableList;
19import com.google.common.collect.Lists;
Hyunsun Moonbc672d62017-04-27 17:08:52 +090020import com.google.common.collect.Maps;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070021import com.google.common.collect.Sets;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070025import org.apache.felix.scr.annotations.Modified;
26import org.apache.felix.scr.annotations.Property;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090027import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.apache.felix.scr.annotations.Service;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070030import org.onlab.packet.IpAddress;
31import org.onlab.packet.TpPort;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090032import org.onlab.util.KryoNamespace;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070033import org.onlab.util.Tools;
34import org.onosproject.cfg.ComponentConfigService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090035import org.onosproject.cluster.ClusterService;
Hyunsun Moon052c71f2016-07-11 18:56:18 -070036import org.onosproject.cluster.ControllerNode;
Daniel Parkad21c572016-03-09 10:18:24 +090037import org.onosproject.cluster.LeadershipService;
38import org.onosproject.cluster.NodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090039import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
daniel parke49eb382017-04-05 16:48:28 +090041import org.onosproject.core.GroupId;
Hyunsun Moon05d9b262016-07-03 18:38:44 -070042import org.onosproject.event.ListenerRegistry;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090043import org.onosproject.net.Device;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.Port;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070046import org.onosproject.net.PortNumber;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090047import org.onosproject.net.behaviour.BridgeConfig;
Hyunsun Moon1251e192016-06-07 16:57:05 -070048import org.onosproject.net.behaviour.BridgeDescription;
Hyunsun Moon052c71f2016-07-11 18:56:18 -070049import org.onosproject.net.behaviour.BridgeName;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090050import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moon1251e192016-06-07 16:57:05 -070051import org.onosproject.net.behaviour.DefaultBridgeDescription;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070052import org.onosproject.net.behaviour.DefaultPatchDescription;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090053import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Moondd14e8e2016-06-09 16:17:32 -070054import org.onosproject.net.behaviour.InterfaceConfig;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070055import org.onosproject.net.behaviour.PatchDescription;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090056import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Moondd14e8e2016-06-09 16:17:32 -070057import org.onosproject.net.behaviour.TunnelEndPoints;
58import org.onosproject.net.behaviour.TunnelKeys;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090059import org.onosproject.net.config.ConfigFactory;
60import org.onosproject.net.config.NetworkConfigEvent;
61import org.onosproject.net.config.NetworkConfigListener;
62import org.onosproject.net.config.NetworkConfigRegistry;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090063import org.onosproject.net.config.basics.SubjectFactories;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090064import org.onosproject.net.device.DeviceEvent;
65import org.onosproject.net.device.DeviceListener;
66import org.onosproject.net.device.DeviceService;
daniel parke49eb382017-04-05 16:48:28 +090067import org.onosproject.net.driver.DriverService;
68import org.onosproject.net.group.Group;
69import org.onosproject.net.group.GroupKey;
70import org.onosproject.net.group.GroupService;
Hyunsun Moon05d9b262016-07-03 18:38:44 -070071import org.onosproject.openstacknode.OpenstackNodeEvent.NodeState;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090072import org.onosproject.ovsdb.controller.OvsdbClientService;
73import org.onosproject.ovsdb.controller.OvsdbController;
74import org.onosproject.ovsdb.controller.OvsdbNodeId;
75import org.onosproject.store.serializers.KryoNamespaces;
76import org.onosproject.store.service.ConsistentMap;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070077import org.onosproject.store.service.MapEvent;
78import org.onosproject.store.service.MapEventListener;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090079import org.onosproject.store.service.Serializer;
80import org.onosproject.store.service.StorageService;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070081import org.onosproject.store.service.Versioned;
82import org.osgi.service.component.ComponentContext;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090083import org.slf4j.Logger;
84
sangho24556ec2016-08-25 10:41:14 +090085import java.util.Dictionary;
sangho24556ec2016-08-25 10:41:14 +090086import java.util.List;
87import java.util.Map;
88import java.util.Objects;
89import java.util.Optional;
90import java.util.Set;
91import java.util.concurrent.ExecutorService;
92import java.util.stream.Collectors;
93
Hyunsun Moon052c71f2016-07-11 18:56:18 -070094import static com.google.common.base.Preconditions.checkArgument;
Daniel Parkad21c572016-03-09 10:18:24 +090095import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090096import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070097import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090098import static org.onosproject.net.Device.Type.SWITCH;
99import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700100import static org.onosproject.openstacknode.Constants.*;
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900101import static org.onosproject.openstacknode.OpenstackNode.getUpdatedNode;
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700102import static org.onosproject.openstacknode.OpenstackNodeEvent.NodeState.*;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900103import static org.slf4j.LoggerFactory.getLogger;
104
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900105/**
106 * Initializes devices in compute/gateway nodes according to there type.
107 */
108@Component(immediate = true)
109@Service
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700110public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEvent, OpenstackNodeListener>
111 implements OpenstackNodeService {
112 private final Logger log = getLogger(getClass());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700113
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900114 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
115 .register(KryoNamespaces.API)
116 .register(OpenstackNode.class)
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700117 .register(NodeType.class)
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900118 .register(NodeState.class);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900119
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700120 private static final String OVSDB_PORT = "ovsdbPort";
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900121 private static final int DPID_BEGIN = 3;
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700122
123 private static final String APP_ID = "org.onosproject.openstacknode";
daniel parke49eb382017-04-05 16:48:28 +0900124
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700125 private static final Class<OpenstackNodeConfig> CONFIG_CLASS = OpenstackNodeConfig.class;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected CoreService coreService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected DeviceService deviceService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700134 protected OvsdbController ovsdbController;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected ClusterService clusterService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900140 protected StorageService storageService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700143 protected ComponentConfigService componentConfigService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
146 protected NetworkConfigRegistry configRegistry;
147
Daniel Parkad21c572016-03-09 10:18:24 +0900148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
149 protected LeadershipService leadershipService;
150
daniel parke49eb382017-04-05 16:48:28 +0900151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 protected DriverService driverService;
153
154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
155 protected GroupService groupService;
156
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700157 @Property(name = OVSDB_PORT, intValue = DEFAULT_OVSDB_PORT,
158 label = "OVSDB server listen port")
159 private int ovsdbPort = DEFAULT_OVSDB_PORT;
160
161 private final ExecutorService eventExecutor =
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700162 newSingleThreadScheduledExecutor(groupedThreads("onos/openstack-node", "event-handler", log));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700163
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900164 private final ConfigFactory configFactory =
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700165 new ConfigFactory<ApplicationId, OpenstackNodeConfig>(
166 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "openstacknode") {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900167 @Override
168 public OpenstackNodeConfig createConfig() {
169 return new OpenstackNodeConfig();
170 }
171 };
172
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700173 private final NetworkConfigListener configListener = new InternalConfigListener();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900174 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700175 private final MapEventListener<String, OpenstackNode> nodeStoreListener = new InternalMapListener();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900176
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700177 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
178 private final BridgeHandler bridgeHandler = new BridgeHandler();
179
180 private ConsistentMap<String, OpenstackNode> nodeStore;
sangho24556ec2016-08-25 10:41:14 +0900181
daniel parke49eb382017-04-05 16:48:28 +0900182 private SelectGroupHandler selectGroupHandler;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900183 private ApplicationId appId;
Daniel Parkad21c572016-03-09 10:18:24 +0900184 private NodeId localNodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900185
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900186 @Activate
187 protected void activate() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700188 appId = coreService.getAppId(APP_ID);
189
Daniel Parkad21c572016-03-09 10:18:24 +0900190 localNodeId = clusterService.getLocalNode().id();
191 leadershipService.runForLeadership(appId.name());
192
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700193 nodeStore = storageService.<String, OpenstackNode>consistentMapBuilder()
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900194 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700195 .withName("openstack-nodestore")
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900196 .withApplicationId(appId)
197 .build();
198
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700199 nodeStore.addListener(nodeStoreListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900200 deviceService.addListener(deviceListener);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700201
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900202 configRegistry.registerConfigFactory(configFactory);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700203 configRegistry.addListener(configListener);
204 componentConfigService.registerProperties(getClass());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900205
daniel parke49eb382017-04-05 16:48:28 +0900206 selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
207
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700208 readConfiguration();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900209 log.info("Started");
210 }
211
212 @Deactivate
213 protected void deactivate() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700214 configRegistry.removeListener(configListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900215 deviceService.removeListener(deviceListener);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700216 nodeStore.removeListener(nodeStoreListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900217
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700218 componentConfigService.unregisterProperties(getClass(), false);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900219 configRegistry.unregisterConfigFactory(configFactory);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700220
Daniel Parkad21c572016-03-09 10:18:24 +0900221 leadershipService.withdraw(appId.name());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700222 eventExecutor.shutdown();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900223
224 log.info("Stopped");
225 }
226
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700227 @Modified
228 protected void modified(ComponentContext context) {
229 Dictionary<?, ?> properties = context.getProperties();
230 int updatedOvsdbPort = Tools.getIntegerProperty(properties, OVSDB_PORT);
231 if (!Objects.equals(updatedOvsdbPort, ovsdbPort)) {
232 ovsdbPort = updatedOvsdbPort;
233 }
234
235 log.info("Modified");
236 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900237
238 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700239 public void addOrUpdateNode(OpenstackNode node) {
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900240 nodeStore.computeIf(node.hostname(),
241 v -> v == null || (!v.equals(node) || v.state() != COMPLETE),
242 (k, v) -> getUpdatedNode(node, nodeState(node))
243 );
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900244 }
245
246 @Override
247 public void deleteNode(OpenstackNode node) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700248 nodeStore.remove(node.hostname());
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700249 process(new OpenstackNodeEvent(INCOMPLETE, node));
250 }
251
252 @Override
253 public void processInitState(OpenstackNode node) {
254 // make sure there is OVSDB connection
255 if (!isOvsdbConnected(node)) {
256 connectOvsdb(node);
257 return;
258 }
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700259 process(new OpenstackNodeEvent(INIT, node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700260
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700261 createBridge(node, INTEGRATION_BRIDGE, node.intBridge());
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700262 if (node.type().equals(NodeType.GATEWAY)) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700263 createBridge(node, ROUTER_BRIDGE, node.routerBridge().get());
264 // TODO remove this when OVSDB provides port event
265 setNodeState(node, nodeState(node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700266 }
267 }
268
269 @Override
270 public void processDeviceCreatedState(OpenstackNode node) {
271 // make sure there is OVSDB connection
272 if (!isOvsdbConnected(node)) {
273 connectOvsdb(node);
274 return;
275 }
daniel park917beb42017-03-16 18:07:15 +0900276
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700277 process(new OpenstackNodeEvent(DEVICE_CREATED, node));
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700278
daniel park917beb42017-03-16 18:07:15 +0900279 if (node.dataIp().isPresent()) {
280 createTunnelInterface(node);
281 }
282
283 if (node.vlanPort().isPresent()) {
284 addVlanPort(node);
285 }
286
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700287 if (node.type().equals(NodeType.GATEWAY)) {
288 createPatchInterface(node);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700289 addUplink(node);
290 // TODO remove this when OVSDB provides port event
291 setNodeState(node, nodeState(node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700292 }
293 }
294
295 @Override
296 public void processCompleteState(OpenstackNode node) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700297 process(new OpenstackNodeEvent(COMPLETE, node));
daniel parke49eb382017-04-05 16:48:28 +0900298 switch (node.type()) {
299 case COMPUTE:
daniel parkee8700b2017-05-11 15:50:03 +0900300 selectGroupHandler.createGatewayGroup(node, gatewayNodes());
daniel parke49eb382017-04-05 16:48:28 +0900301 break;
302 case GATEWAY:
303 updateGatewayGroup(node, true);
304 break;
305 default:
306 break;
307 }
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700308 log.info("Finished init {}", node.hostname());
309 }
310
311 @Override
312 public void processIncompleteState(OpenstackNode node) {
313 process(new OpenstackNodeEvent(INCOMPLETE, node));
daniel parke49eb382017-04-05 16:48:28 +0900314 if (node.type().equals(NodeType.GATEWAY)) {
315 updateGatewayGroup(node, false);
316 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900317 }
318
319 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700320 public List<OpenstackNode> nodes() {
321 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900322 }
323
324 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700325 public Set<OpenstackNode> completeNodes() {
326 return nodeStore.values().stream().map(Versioned::value)
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700327 .filter(node -> node.state().equals(COMPLETE))
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700328 .collect(Collectors.toSet());
329 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900330
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700331 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700332 public Optional<IpAddress> dataIp(DeviceId deviceId) {
333 OpenstackNode node = nodeByDeviceId(deviceId);
334 if (node == null) {
335 log.warn("Failed to get node for {}", deviceId);
336 return Optional.empty();
337 }
daniel park917beb42017-03-16 18:07:15 +0900338 return node.dataIp();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700339 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900340
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700341 @Override
342 public Optional<PortNumber> tunnelPort(DeviceId deviceId) {
343 return deviceService.getPorts(deviceId).stream()
344 .filter(p -> p.annotations().value(PORT_NAME).equals(DEFAULT_TUNNEL) &&
345 p.isEnabled())
346 .map(Port::number).findFirst();
347 }
348
349 @Override
daniel parka792cf72017-04-14 16:25:35 +0900350 public Optional<PortNumber> vlanPort(DeviceId intBridgeId) {
351 Optional<String> vlanPortName = nodeByDeviceId(intBridgeId).vlanPort();
352
353 return deviceService.getPorts(intBridgeId).stream()
354 .filter(p -> p.annotations().value(PORT_NAME).equals(vlanPortName.get()) &&
355 p.isEnabled())
356 .map(Port::number).findFirst();
357
358 }
359
360 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700361 public Optional<DeviceId> routerBridge(DeviceId intBridgeId) {
362 OpenstackNode node = nodeByDeviceId(intBridgeId);
363 if (node == null || node.type().equals(NodeType.COMPUTE)) {
364 log.warn("Failed to find router bridge connected to {}", intBridgeId);
365 return Optional.empty();
366 }
367 return node.routerBridge();
368 }
369
370 @Override
371 public Optional<PortNumber> externalPort(DeviceId intBridgeId) {
372 return deviceService.getPorts(intBridgeId).stream()
373 .filter(p -> p.annotations().value(PORT_NAME).equals(PATCH_INTG_BRIDGE) &&
374 p.isEnabled())
375 .map(Port::number).findFirst();
376 }
377
daniel parke49eb382017-04-05 16:48:28 +0900378 @Override
379 public OpenstackNode gatewayNode(DeviceId deviceId) {
380 OpenstackNode gatewayNode = nodeByDeviceId(deviceId);
381 if (gatewayNode == null) {
382 log.warn("Gateway with device ID {} does not exist");
383 return null;
384 }
385 return gatewayNode;
386 }
387
388 @Override
daniel parkee8700b2017-05-11 15:50:03 +0900389 public synchronized GroupId gatewayGroupId(DeviceId srcDeviceId, NetworkMode networkMode) {
390 GroupKey groupKey = selectGroupHandler.groupKey(srcDeviceId, networkMode);
daniel parke49eb382017-04-05 16:48:28 +0900391 Group group = groupService.getGroup(srcDeviceId, groupKey);
daniel parkee8700b2017-05-11 15:50:03 +0900392
daniel parke49eb382017-04-05 16:48:28 +0900393 if (group == null) {
394 log.info("Created gateway group for {}", srcDeviceId);
daniel parkee8700b2017-05-11 15:50:03 +0900395 selectGroupHandler.createGatewayGroup(nodeByDeviceId(srcDeviceId), gatewayNodes());
396
397 return groupService.getGroup(srcDeviceId, selectGroupHandler.groupKey(srcDeviceId, networkMode)).id();
daniel parke49eb382017-04-05 16:48:28 +0900398 } else {
399 return group.id();
400 }
401 }
402
403 @Override
404 public List<OpenstackNode> gatewayNodes() {
405 return nodeStore.values()
406 .stream()
407 .map(Versioned::value)
408 .filter(node -> node.type().equals(NodeType.GATEWAY))
409 .filter(node -> node.state().equals(COMPLETE))
410 .collect(Collectors.toList());
411 }
412
413 @Override
414 public List<DeviceId> gatewayDeviceIds() {
415 List<DeviceId> deviceIdList = Lists.newArrayList();
416
417 nodeStore.values()
418 .stream()
419 .map(Versioned::value)
420 .filter(node -> node.type().equals(NodeType.GATEWAY))
421 .filter(node -> node.state().equals(COMPLETE))
422 .forEach(node -> deviceIdList.add(node.intBridge()));
423 return deviceIdList;
424 }
425
426 private void updateGatewayGroup(OpenstackNode gatewayNode, boolean isInsert) {
427 nodeStore.values()
428 .stream()
429 .map(Versioned::value)
430 .filter(node -> node.type().equals(NodeType.COMPUTE))
daniel parkee8700b2017-05-11 15:50:03 +0900431 .filter(node -> node.dataIp().isPresent())
daniel parke49eb382017-04-05 16:48:28 +0900432 .filter(node -> node.state().equals(COMPLETE))
daniel parkee8700b2017-05-11 15:50:03 +0900433 .forEach(computeNode -> {
434 selectGroupHandler.updateGatewayGroupBuckets(computeNode,
435 ImmutableList.of(gatewayNode), NetworkMode.VXLAN, isInsert);
436 log.trace("Updated gateway group on {} for vxlan mode", computeNode.intBridge());
daniel parke49eb382017-04-05 16:48:28 +0900437 });
daniel parkee8700b2017-05-11 15:50:03 +0900438
439 nodeStore.values()
440 .stream()
441 .map(Versioned::value)
442 .filter(node -> node.type().equals(NodeType.COMPUTE))
443 .filter(node -> node.vlanPort().isPresent())
444 .filter(node -> node.state().equals(COMPLETE))
445 .forEach(computeNode -> {
446 selectGroupHandler.updateGatewayGroupBuckets(computeNode,
447 ImmutableList.of(gatewayNode), NetworkMode.VLAN, isInsert);
448 log.trace("Updated gateway group on {} for vlan mode", computeNode.intBridge());
449 });
450
daniel parke49eb382017-04-05 16:48:28 +0900451 }
452
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700453 private void initNode(OpenstackNode node) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700454 NodeState state = node.state();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700455 state.process(this, node);
456 log.debug("Processing node: {} state: {}", node.hostname(), state);
457 }
458
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700459 private void setNodeState(OpenstackNode node, NodeState newState) {
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900460 nodeStore.put(node.hostname(), getUpdatedNode(node, newState));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700461 }
462
463 private NodeState nodeState(OpenstackNode node) {
Frank Wang39b95772017-03-01 15:35:13 +0800464 if (!isOvsdbConnected(node) || !deviceService.isAvailable(node.intBridge()) ||
465 !isBridgeCreated(node.ovsdbId(), INTEGRATION_BRIDGE)) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700466 return INIT;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900467 }
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700468
469 // TODO use device service when we use single ONOS cluster for both openstackNode and vRouter
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700470 if (node.type().equals(NodeType.GATEWAY) &&
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700471 !isBridgeCreated(node.ovsdbId(), ROUTER_BRIDGE)) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700472 return INIT;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900473 }
474
daniel park917beb42017-03-16 18:07:15 +0900475 if (node.dataIp().isPresent() && !isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
476 return DEVICE_CREATED;
477 }
478
479 if (node.vlanPort().isPresent() && !isIfaceCreated(node.ovsdbId(), node.vlanPort().get())) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700480 return DEVICE_CREATED;
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700481 }
482
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700483 if (node.type().equals(NodeType.GATEWAY) && (
484 !isIfaceCreated(node.ovsdbId(), PATCH_ROUT_BRIDGE) ||
485 !isIfaceCreated(node.ovsdbId(), PATCH_INTG_BRIDGE) ||
486 !isIfaceCreated(node.ovsdbId(), node.uplink().get()))) {
487 return DEVICE_CREATED;
488 }
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700489 return COMPLETE;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900490 }
491
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700492 private boolean isIfaceCreated(DeviceId deviceId, String ifaceName) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700493 Device device = deviceService.getDevice(deviceId);
494 if (device == null || !device.is(BridgeConfig.class)) {
495 return false;
496 }
497
498 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
499 return bridgeConfig.getPorts().stream()
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900500 .anyMatch(port -> port.annotations().value(PORT_NAME).equals(ifaceName));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700501 }
502
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700503 private boolean isBridgeCreated(DeviceId deviceId, String bridgeName) {
504 Device device = deviceService.getDevice(deviceId);
505 if (device == null || !device.is(BridgeConfig.class)) {
506 return false;
507 }
508
509 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
510 return bridgeConfig.getBridges().stream()
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900511 .anyMatch(bridge -> bridge.name().equals(bridgeName));
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700512 }
513
514 private void createBridge(OpenstackNode node, String bridgeName, DeviceId deviceId) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700515 Device device = deviceService.getDevice(node.ovsdbId());
516 if (device == null || !device.is(BridgeConfig.class)) {
517 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900518 return;
519 }
520
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700521 // TODO fix this when we use single ONOS cluster for both openstackNode and vRouter
522 Set<IpAddress> controllerIps;
523 if (bridgeName.equals(ROUTER_BRIDGE)) {
524 controllerIps = Sets.newHashSet(node.routerController().get());
525 } else {
526 controllerIps = clusterService.getNodes().stream()
527 .map(ControllerNode::ip)
528 .collect(Collectors.toSet());
529 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900530
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700531 List<ControllerInfo> controllers = controllerIps.stream()
532 .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
533 .collect(Collectors.toList());
534
535 String dpid = deviceId.toString().substring(DPID_BEGIN);
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700536 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700537 .name(bridgeName)
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700538 .failMode(BridgeDescription.FailMode.SECURE)
539 .datapathId(dpid)
540 .disableInBand()
541 .controllers(controllers)
542 .build();
543
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700544 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700545 bridgeConfig.addBridge(bridgeDesc);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900546 }
547
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900548 private void createTunnelInterface(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700549 if (isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
550 return;
551 }
552
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700553 Device device = deviceService.getDevice(node.ovsdbId());
554 if (device == null || !device.is(InterfaceConfig.class)) {
555 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900556 return;
557 }
558
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700559 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
560 .deviceId(INTEGRATION_BRIDGE)
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700561 .ifaceName(DEFAULT_TUNNEL)
562 .type(VXLAN)
563 .remote(TunnelEndPoints.flowTunnelEndpoint())
564 .key(TunnelKeys.flowTunnelKey())
565 .build();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700566
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700567 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700568 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900569 }
570
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700571 private void createPatchInterface(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700572 checkArgument(node.type().equals(NodeType.GATEWAY));
573 if (isIfaceCreated(node.ovsdbId(), PATCH_INTG_BRIDGE) &&
574 isIfaceCreated(node.ovsdbId(), PATCH_ROUT_BRIDGE)) {
575 return;
576 }
577
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700578 Device device = deviceService.getDevice(node.ovsdbId());
579 if (device == null || !device.is(InterfaceConfig.class)) {
580 log.error("Failed to create patch interfaces on {}", node.hostname());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900581 return;
582 }
583
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700584 PatchDescription patchIntg = DefaultPatchDescription.builder()
585 .deviceId(INTEGRATION_BRIDGE)
586 .ifaceName(PATCH_INTG_BRIDGE)
587 .peer(PATCH_ROUT_BRIDGE)
588 .build();
589
590 PatchDescription patchRout = DefaultPatchDescription.builder()
591 .deviceId(ROUTER_BRIDGE)
592 .ifaceName(PATCH_ROUT_BRIDGE)
593 .peer(PATCH_INTG_BRIDGE)
594 .build();
595
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700596 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700597 ifaceConfig.addPatchMode(PATCH_INTG_BRIDGE, patchIntg);
598 ifaceConfig.addPatchMode(PATCH_ROUT_BRIDGE, patchRout);
599 }
600
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700601 private void addUplink(OpenstackNode node) {
602 checkArgument(node.type().equals(NodeType.GATEWAY));
603 if (isIfaceCreated(node.ovsdbId(), node.uplink().get())) {
604 return;
605 }
606
607 Device device = deviceService.getDevice(node.ovsdbId());
608 if (device == null || !device.is(BridgeConfig.class)) {
609 log.error("Failed to add port {} on {}", node.uplink().get(), node.ovsdbId());
610 return;
611 }
612
613 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
614 bridgeConfig.addPort(BridgeName.bridgeName(ROUTER_BRIDGE),
615 node.uplink().get());
616 }
617
daniel park917beb42017-03-16 18:07:15 +0900618 private void addVlanPort(OpenstackNode node) {
619 if (isIfaceCreated(node.ovsdbId(), node.vlanPort().get())) {
620 return;
621 }
622
623 Device device = deviceService.getDevice(node.ovsdbId());
624 if (device == null || !device.is(BridgeConfig.class)) {
625 log.error("Failed to add port {} on {}", node.vlanPort().get(), node.ovsdbId());
626 return;
627 }
628
629 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
630 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE),
631 node.vlanPort().get());
632 }
633
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700634 private boolean isOvsdbConnected(OpenstackNode node) {
635 OvsdbNodeId ovsdb = new OvsdbNodeId(node.managementIp(), ovsdbPort);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700636 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700637 return deviceService.isAvailable(node.ovsdbId()) &&
638 client != null &&
639 client.isConnected();
640 }
641
642 private void connectOvsdb(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700643 ovsdbController.connect(node.managementIp(), TpPort.tpPort(ovsdbPort));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700644 }
645
646 private Set<String> systemIfaces(OpenstackNode node) {
daniel park917beb42017-03-16 18:07:15 +0900647 Set<String> ifaces = Sets.newHashSet();
648 node.dataIp().ifPresent(ip -> ifaces.add(DEFAULT_TUNNEL));
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900649 node.vlanPort().ifPresent(ifaces::add);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700650 if (node.type().equals(NodeType.GATEWAY)) {
651 ifaces.add(PATCH_INTG_BRIDGE);
652 ifaces.add(PATCH_ROUT_BRIDGE);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700653 ifaces.add(node.uplink().get());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700654 }
655 return ifaces;
656 }
657
658 private OpenstackNode nodeByDeviceId(DeviceId deviceId) {
659 OpenstackNode node = nodes().stream()
660 .filter(n -> n.intBridge().equals(deviceId))
661 .findFirst().orElseGet(() -> nodes().stream()
662 .filter(n -> n.routerBridge().isPresent())
663 .filter(n -> n.routerBridge().get().equals(deviceId))
Frank Wang39b95772017-03-01 15:35:13 +0800664 .findFirst().orElseGet(() -> nodes().stream()
665 .filter(n -> n.ovsdbId().equals(deviceId))
666 .findFirst().orElse(null)));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700667 return node;
668 }
669
670 private class OvsdbHandler implements ConnectionHandler<Device> {
671
672 @Override
673 public void connected(Device device) {
674 OpenstackNode node = nodes().stream()
675 .filter(n -> n.ovsdbId().equals(device.id()))
676 .findFirst()
677 .orElse(null);
678 if (node != null) {
679 setNodeState(node, nodeState(node));
680 } else {
681 log.debug("{} is detected on unregistered node, ignore it.", device.id());
682 }
683 }
684
685 @Override
686 public void disconnected(Device device) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700687 OpenstackNode node = nodeByDeviceId(device.id());
688 if (node != null) {
689 log.warn("Device {} is disconnected", device.id());
690 setNodeState(node, NodeState.INCOMPLETE);
691 }
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700692 }
693 }
694
695 private class BridgeHandler implements ConnectionHandler<Device> {
696
697 @Override
698 public void connected(Device device) {
699 OpenstackNode node = nodeByDeviceId(device.id());
700 if (node != null) {
701 setNodeState(node, nodeState(node));
702 } else {
703 log.debug("{} is detected on unregistered node, ignore it.", device.id());
704 }
705 }
706
707 @Override
708 public void disconnected(Device device) {
709 OpenstackNode node = nodeByDeviceId(device.id());
710 if (node != null) {
711 log.warn("Device {} is disconnected", device.id());
712 setNodeState(node, NodeState.INCOMPLETE);
713 }
714 }
715
716 /**
717 * Handles port added situation.
718 * If the added port is tunnel or data plane interface, proceed to the remaining
719 * node initialization. Otherwise, do nothing.
720 *
721 * @param port port
722 */
723 public void portAdded(Port port) {
724 OpenstackNode node = nodeByDeviceId((DeviceId) port.element().id());
725 String portName = port.annotations().value(PORT_NAME);
726 if (node == null) {
727 log.debug("{} is added to unregistered node, ignore it.", portName);
728 return;
729 }
730
731 log.info("Port {} is added to {}", portName, node.hostname());
732 if (systemIfaces(node).contains(portName)) {
733 setNodeState(node, nodeState(node));
734 }
735 }
736
737 /**
738 * Handles port removed situation.
739 * If the removed port is tunnel or data plane interface, proceed to the remaining
740 * node initialization.Others, do nothing.
741 *
742 * @param port port
743 */
744 public void portRemoved(Port port) {
745 OpenstackNode node = nodeByDeviceId((DeviceId) port.element().id());
746 String portName = port.annotations().value(PORT_NAME);
747
748 if (node == null) {
749 return;
750 }
751
752 log.info("Port {} is removed from {}", portName, node.hostname());
753 if (systemIfaces(node).contains(portName)) {
754 setNodeState(node, NodeState.INCOMPLETE);
755 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900756 }
757 }
758
759 private class InternalDeviceListener implements DeviceListener {
760
761 @Override
762 public void event(DeviceEvent event) {
Daniel Parkad21c572016-03-09 10:18:24 +0900763
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700764 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
765 if (!Objects.equals(localNodeId, leaderNodeId)) {
766 // do not allow to proceed without leadership
Daniel Parkad21c572016-03-09 10:18:24 +0900767 return;
768 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900769
770 Device device = event.subject();
771 ConnectionHandler<Device> handler =
772 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
773
774 switch (event.type()) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700775 // TODO implement OVSDB port event so that we can handle updates on the OVSDB
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900776 case PORT_ADDED:
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700777 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900778 break;
779 case PORT_UPDATED:
780 if (!event.port().isEnabled()) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700781 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900782 }
783 break;
784 case DEVICE_ADDED:
785 case DEVICE_AVAILABILITY_CHANGED:
786 if (deviceService.isAvailable(device.id())) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700787 eventExecutor.execute(() -> handler.connected(device));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900788 } else {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700789 eventExecutor.execute(() -> handler.disconnected(device));
daniel parke49eb382017-04-05 16:48:28 +0900790 log.warn("OpenstackNode with device ID {} is disconnected", device.id());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900791 }
792 break;
793 default:
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900794 break;
795 }
796 }
797 }
798
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900799 private void readConfiguration() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700800 OpenstackNodeConfig config = configRegistry.getConfig(appId, CONFIG_CLASS);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900801 if (config == null) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700802 log.debug("No configuration found");
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900803 return;
804 }
sangho24556ec2016-08-25 10:41:14 +0900805
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900806 Map<String, OpenstackNode> prevNodeMap = Maps.newHashMap(nodeStore.asJavaMap());
sangho24556ec2016-08-25 10:41:14 +0900807 config.openstackNodes().forEach(node -> {
808 prevNodeMap.remove(node.hostname());
809 addOrUpdateNode(node);
810 });
Sho SHIMIZU8ebb04a2016-10-06 15:58:29 -0700811 prevNodeMap.values().forEach(this::deleteNode);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900812 }
813
814 private class InternalConfigListener implements NetworkConfigListener {
815
816 @Override
817 public void event(NetworkConfigEvent event) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700818 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
819 if (!Objects.equals(localNodeId, leaderNodeId)) {
820 // do not allow to proceed without leadership
821 return;
822 }
823
824 if (!event.configClass().equals(CONFIG_CLASS)) {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900825 return;
826 }
827
828 switch (event.type()) {
829 case CONFIG_ADDED:
830 case CONFIG_UPDATED:
831 eventExecutor.execute(OpenstackNodeManager.this::readConfiguration);
832 break;
833 default:
834 break;
835 }
836 }
837 }
838
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700839 private class InternalMapListener implements MapEventListener<String, OpenstackNode> {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900840
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700841 @Override
842 public void event(MapEvent<String, OpenstackNode> event) {
843 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
844 if (!Objects.equals(localNodeId, leaderNodeId)) {
845 // do not allow to proceed without leadership
846 return;
847 }
848
849 OpenstackNode oldNode;
850 OpenstackNode newNode;
851
852 switch (event.type()) {
853 case UPDATE:
854 oldNode = event.oldValue().value();
855 newNode = event.newValue().value();
856
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700857 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700858 if (!newNode.equals(oldNode)) {
859 log.debug("New node: {}", newNode);
860 }
861 // performs init procedure even if the node is not changed
862 // for robustness since it's no harm to run init procedure
863 // multiple times
864 eventExecutor.execute(() -> initNode(newNode));
865 break;
866 case INSERT:
867 newNode = event.newValue().value();
868 log.info("Added {}", newNode.hostname());
869 eventExecutor.execute(() -> initNode(newNode));
870 break;
871 case REMOVE:
872 oldNode = event.oldValue().value();
873 log.info("Removed {}", oldNode.hostname());
874 break;
875 default:
876 break;
877 }
878 }
879 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900880}