blob: 3eb8095022164d483752095d27d7f52ca6f0260f [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;
Hyunsun Moonbc672d62017-04-27 17:08:52 +090019import com.google.common.collect.Maps;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070020import com.google.common.collect.Sets;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070024import org.apache.felix.scr.annotations.Modified;
25import org.apache.felix.scr.annotations.Property;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.apache.felix.scr.annotations.Service;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070029import org.onlab.packet.IpAddress;
30import org.onlab.packet.TpPort;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090031import org.onlab.util.KryoNamespace;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070032import org.onlab.util.Tools;
33import org.onosproject.cfg.ComponentConfigService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090034import org.onosproject.cluster.ClusterService;
Hyunsun Moon052c71f2016-07-11 18:56:18 -070035import org.onosproject.cluster.ControllerNode;
Daniel Parkad21c572016-03-09 10:18:24 +090036import org.onosproject.cluster.LeadershipService;
37import org.onosproject.cluster.NodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
daniel parke49eb382017-04-05 16:48:28 +090040import org.onosproject.core.GroupId;
Hyunsun Moon05d9b262016-07-03 18:38:44 -070041import org.onosproject.event.ListenerRegistry;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090042import org.onosproject.net.Device;
43import org.onosproject.net.DeviceId;
44import org.onosproject.net.Port;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070045import org.onosproject.net.PortNumber;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090046import org.onosproject.net.behaviour.BridgeConfig;
Hyunsun Moon1251e192016-06-07 16:57:05 -070047import org.onosproject.net.behaviour.BridgeDescription;
Hyunsun Moon052c71f2016-07-11 18:56:18 -070048import org.onosproject.net.behaviour.BridgeName;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090049import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moon1251e192016-06-07 16:57:05 -070050import org.onosproject.net.behaviour.DefaultBridgeDescription;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070051import org.onosproject.net.behaviour.DefaultPatchDescription;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090052import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Moondd14e8e2016-06-09 16:17:32 -070053import org.onosproject.net.behaviour.InterfaceConfig;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070054import org.onosproject.net.behaviour.PatchDescription;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090055import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Moondd14e8e2016-06-09 16:17:32 -070056import org.onosproject.net.behaviour.TunnelEndPoints;
57import org.onosproject.net.behaviour.TunnelKeys;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090058import org.onosproject.net.config.ConfigFactory;
59import org.onosproject.net.config.NetworkConfigEvent;
60import org.onosproject.net.config.NetworkConfigListener;
61import org.onosproject.net.config.NetworkConfigRegistry;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090062import org.onosproject.net.config.basics.SubjectFactories;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090063import org.onosproject.net.device.DeviceEvent;
64import org.onosproject.net.device.DeviceListener;
65import org.onosproject.net.device.DeviceService;
daniel parke49eb382017-04-05 16:48:28 +090066import org.onosproject.net.driver.DriverService;
67import org.onosproject.net.group.Group;
68import org.onosproject.net.group.GroupKey;
69import org.onosproject.net.group.GroupService;
Hyunsun Moon05d9b262016-07-03 18:38:44 -070070import org.onosproject.openstacknode.OpenstackNodeEvent.NodeState;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090071import org.onosproject.ovsdb.controller.OvsdbClientService;
72import org.onosproject.ovsdb.controller.OvsdbController;
73import org.onosproject.ovsdb.controller.OvsdbNodeId;
74import org.onosproject.store.serializers.KryoNamespaces;
75import org.onosproject.store.service.ConsistentMap;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070076import org.onosproject.store.service.MapEvent;
77import org.onosproject.store.service.MapEventListener;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090078import org.onosproject.store.service.Serializer;
79import org.onosproject.store.service.StorageService;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070080import org.onosproject.store.service.Versioned;
81import org.osgi.service.component.ComponentContext;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090082import org.slf4j.Logger;
83
sangho24556ec2016-08-25 10:41:14 +090084import java.util.Dictionary;
sangho24556ec2016-08-25 10:41:14 +090085import java.util.List;
86import java.util.Map;
87import java.util.Objects;
88import java.util.Optional;
89import java.util.Set;
90import java.util.concurrent.ExecutorService;
91import java.util.stream.Collectors;
92
Hyunsun Moon052c71f2016-07-11 18:56:18 -070093import static com.google.common.base.Preconditions.checkArgument;
Daniel Parkad21c572016-03-09 10:18:24 +090094import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090095import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070096import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090097import static org.onosproject.net.Device.Type.SWITCH;
98import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070099import static org.onosproject.openstacknode.Constants.*;
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900100import static org.onosproject.openstacknode.OpenstackNode.getUpdatedNode;
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700101import static org.onosproject.openstacknode.OpenstackNodeEvent.NodeState.*;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900102import static org.slf4j.LoggerFactory.getLogger;
103
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900104/**
105 * Initializes devices in compute/gateway nodes according to there type.
106 */
107@Component(immediate = true)
108@Service
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700109public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEvent, OpenstackNodeListener>
110 implements OpenstackNodeService {
111 private final Logger log = getLogger(getClass());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700112
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900113 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
114 .register(KryoNamespaces.API)
115 .register(OpenstackNode.class)
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700116 .register(NodeType.class)
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900117 .register(NodeState.class);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900118
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700119 private static final String OVSDB_PORT = "ovsdbPort";
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900120 private static final int DPID_BEGIN = 3;
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700121
122 private static final String APP_ID = "org.onosproject.openstacknode";
daniel parke49eb382017-04-05 16:48:28 +0900123
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700124 private static final Class<OpenstackNodeConfig> CONFIG_CLASS = OpenstackNodeConfig.class;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected CoreService coreService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected DeviceService deviceService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700133 protected OvsdbController ovsdbController;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected ClusterService clusterService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900139 protected StorageService storageService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700142 protected ComponentConfigService componentConfigService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected NetworkConfigRegistry configRegistry;
146
Daniel Parkad21c572016-03-09 10:18:24 +0900147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected LeadershipService leadershipService;
149
daniel parke49eb382017-04-05 16:48:28 +0900150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
151 protected DriverService driverService;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
154 protected GroupService groupService;
155
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700156 @Property(name = OVSDB_PORT, intValue = DEFAULT_OVSDB_PORT,
157 label = "OVSDB server listen port")
158 private int ovsdbPort = DEFAULT_OVSDB_PORT;
159
160 private final ExecutorService eventExecutor =
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700161 newSingleThreadScheduledExecutor(groupedThreads("onos/openstack-node", "event-handler", log));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700162
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900163 private final ConfigFactory configFactory =
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700164 new ConfigFactory<ApplicationId, OpenstackNodeConfig>(
165 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "openstacknode") {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900166 @Override
167 public OpenstackNodeConfig createConfig() {
168 return new OpenstackNodeConfig();
169 }
170 };
171
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700172 private final NetworkConfigListener configListener = new InternalConfigListener();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900173 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700174 private final MapEventListener<String, OpenstackNode> nodeStoreListener = new InternalMapListener();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900175
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700176 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
177 private final BridgeHandler bridgeHandler = new BridgeHandler();
178
179 private ConsistentMap<String, OpenstackNode> nodeStore;
sangho24556ec2016-08-25 10:41:14 +0900180
daniel parke49eb382017-04-05 16:48:28 +0900181 private SelectGroupHandler selectGroupHandler;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900182 private ApplicationId appId;
Daniel Parkad21c572016-03-09 10:18:24 +0900183 private NodeId localNodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900184
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900185 @Activate
186 protected void activate() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700187 appId = coreService.getAppId(APP_ID);
188
Daniel Parkad21c572016-03-09 10:18:24 +0900189 localNodeId = clusterService.getLocalNode().id();
190 leadershipService.runForLeadership(appId.name());
191
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700192 nodeStore = storageService.<String, OpenstackNode>consistentMapBuilder()
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900193 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700194 .withName("openstack-nodestore")
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900195 .withApplicationId(appId)
196 .build();
197
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700198 nodeStore.addListener(nodeStoreListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900199 deviceService.addListener(deviceListener);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700200
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900201 configRegistry.registerConfigFactory(configFactory);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700202 configRegistry.addListener(configListener);
203 componentConfigService.registerProperties(getClass());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900204
daniel parke49eb382017-04-05 16:48:28 +0900205 selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
206
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700207 readConfiguration();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900208 log.info("Started");
209 }
210
211 @Deactivate
212 protected void deactivate() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700213 configRegistry.removeListener(configListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900214 deviceService.removeListener(deviceListener);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700215 nodeStore.removeListener(nodeStoreListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900216
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700217 componentConfigService.unregisterProperties(getClass(), false);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900218 configRegistry.unregisterConfigFactory(configFactory);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700219
Daniel Parkad21c572016-03-09 10:18:24 +0900220 leadershipService.withdraw(appId.name());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700221 eventExecutor.shutdown();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900222
223 log.info("Stopped");
224 }
225
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700226 @Modified
227 protected void modified(ComponentContext context) {
228 Dictionary<?, ?> properties = context.getProperties();
229 int updatedOvsdbPort = Tools.getIntegerProperty(properties, OVSDB_PORT);
230 if (!Objects.equals(updatedOvsdbPort, ovsdbPort)) {
231 ovsdbPort = updatedOvsdbPort;
232 }
233
234 log.info("Modified");
235 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900236
237 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700238 public void addOrUpdateNode(OpenstackNode node) {
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900239 nodeStore.computeIf(node.hostname(),
240 v -> v == null || (!v.equals(node) || v.state() != COMPLETE),
241 (k, v) -> getUpdatedNode(node, nodeState(node))
242 );
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900243 }
244
245 @Override
246 public void deleteNode(OpenstackNode node) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700247 nodeStore.remove(node.hostname());
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700248 process(new OpenstackNodeEvent(INCOMPLETE, node));
249 }
250
251 @Override
252 public void processInitState(OpenstackNode node) {
253 // make sure there is OVSDB connection
254 if (!isOvsdbConnected(node)) {
255 connectOvsdb(node);
256 return;
257 }
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700258 process(new OpenstackNodeEvent(INIT, node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700259
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700260 createBridge(node, INTEGRATION_BRIDGE, node.intBridge());
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700261 if (node.type().equals(NodeType.GATEWAY)) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700262 createBridge(node, ROUTER_BRIDGE, node.routerBridge().get());
263 // TODO remove this when OVSDB provides port event
264 setNodeState(node, nodeState(node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700265 }
266 }
267
268 @Override
269 public void processDeviceCreatedState(OpenstackNode node) {
270 // make sure there is OVSDB connection
271 if (!isOvsdbConnected(node)) {
272 connectOvsdb(node);
273 return;
274 }
daniel park917beb42017-03-16 18:07:15 +0900275
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700276 process(new OpenstackNodeEvent(DEVICE_CREATED, node));
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700277
daniel park917beb42017-03-16 18:07:15 +0900278 if (node.dataIp().isPresent()) {
279 createTunnelInterface(node);
280 }
281
282 if (node.vlanPort().isPresent()) {
283 addVlanPort(node);
284 }
285
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700286 if (node.type().equals(NodeType.GATEWAY)) {
287 createPatchInterface(node);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700288 addUplink(node);
289 // TODO remove this when OVSDB provides port event
290 setNodeState(node, nodeState(node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700291 }
292 }
293
294 @Override
295 public void processCompleteState(OpenstackNode node) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700296 process(new OpenstackNodeEvent(COMPLETE, node));
daniel parke49eb382017-04-05 16:48:28 +0900297 switch (node.type()) {
298 case COMPUTE:
daniel parkee8700b2017-05-11 15:50:03 +0900299 selectGroupHandler.createGatewayGroup(node, gatewayNodes());
daniel parke49eb382017-04-05 16:48:28 +0900300 break;
301 case GATEWAY:
302 updateGatewayGroup(node, true);
303 break;
304 default:
305 break;
306 }
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700307 log.info("Finished init {}", node.hostname());
308 }
309
310 @Override
311 public void processIncompleteState(OpenstackNode node) {
312 process(new OpenstackNodeEvent(INCOMPLETE, node));
daniel parke49eb382017-04-05 16:48:28 +0900313 if (node.type().equals(NodeType.GATEWAY)) {
314 updateGatewayGroup(node, false);
315 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900316 }
317
318 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700319 public List<OpenstackNode> nodes() {
320 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900321 }
322
323 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700324 public Set<OpenstackNode> completeNodes() {
325 return nodeStore.values().stream().map(Versioned::value)
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700326 .filter(node -> node.state().equals(COMPLETE))
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700327 .collect(Collectors.toSet());
328 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900329
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700330 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700331 public Optional<IpAddress> dataIp(DeviceId deviceId) {
332 OpenstackNode node = nodeByDeviceId(deviceId);
333 if (node == null) {
334 log.warn("Failed to get node for {}", deviceId);
335 return Optional.empty();
336 }
daniel park917beb42017-03-16 18:07:15 +0900337 return node.dataIp();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700338 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900339
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700340 @Override
341 public Optional<PortNumber> tunnelPort(DeviceId deviceId) {
342 return deviceService.getPorts(deviceId).stream()
343 .filter(p -> p.annotations().value(PORT_NAME).equals(DEFAULT_TUNNEL) &&
344 p.isEnabled())
345 .map(Port::number).findFirst();
346 }
347
348 @Override
daniel parka792cf72017-04-14 16:25:35 +0900349 public Optional<PortNumber> vlanPort(DeviceId intBridgeId) {
350 Optional<String> vlanPortName = nodeByDeviceId(intBridgeId).vlanPort();
351
352 return deviceService.getPorts(intBridgeId).stream()
353 .filter(p -> p.annotations().value(PORT_NAME).equals(vlanPortName.get()) &&
354 p.isEnabled())
355 .map(Port::number).findFirst();
356
357 }
358
359 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700360 public Optional<DeviceId> routerBridge(DeviceId intBridgeId) {
361 OpenstackNode node = nodeByDeviceId(intBridgeId);
362 if (node == null || node.type().equals(NodeType.COMPUTE)) {
363 log.warn("Failed to find router bridge connected to {}", intBridgeId);
364 return Optional.empty();
365 }
366 return node.routerBridge();
367 }
368
369 @Override
370 public Optional<PortNumber> externalPort(DeviceId intBridgeId) {
371 return deviceService.getPorts(intBridgeId).stream()
372 .filter(p -> p.annotations().value(PORT_NAME).equals(PATCH_INTG_BRIDGE) &&
373 p.isEnabled())
374 .map(Port::number).findFirst();
375 }
376
daniel parke49eb382017-04-05 16:48:28 +0900377 @Override
378 public OpenstackNode gatewayNode(DeviceId deviceId) {
379 OpenstackNode gatewayNode = nodeByDeviceId(deviceId);
Frank Wang894c7182017-06-02 15:49:08 +0800380 if (gatewayNode == null || gatewayNode.type() != NodeType.GATEWAY) {
daniel parke49eb382017-04-05 16:48:28 +0900381 log.warn("Gateway with device ID {} does not exist");
382 return null;
383 }
384 return gatewayNode;
385 }
386
387 @Override
daniel parkee8700b2017-05-11 15:50:03 +0900388 public synchronized GroupId gatewayGroupId(DeviceId srcDeviceId, NetworkMode networkMode) {
389 GroupKey groupKey = selectGroupHandler.groupKey(srcDeviceId, networkMode);
daniel parke49eb382017-04-05 16:48:28 +0900390 Group group = groupService.getGroup(srcDeviceId, groupKey);
daniel parkee8700b2017-05-11 15:50:03 +0900391
daniel parke49eb382017-04-05 16:48:28 +0900392 if (group == null) {
393 log.info("Created gateway group for {}", srcDeviceId);
daniel parkee8700b2017-05-11 15:50:03 +0900394 selectGroupHandler.createGatewayGroup(nodeByDeviceId(srcDeviceId), gatewayNodes());
395
396 return groupService.getGroup(srcDeviceId, selectGroupHandler.groupKey(srcDeviceId, networkMode)).id();
daniel parke49eb382017-04-05 16:48:28 +0900397 } else {
398 return group.id();
399 }
400 }
401
402 @Override
403 public List<OpenstackNode> gatewayNodes() {
404 return nodeStore.values()
405 .stream()
406 .map(Versioned::value)
407 .filter(node -> node.type().equals(NodeType.GATEWAY))
408 .filter(node -> node.state().equals(COMPLETE))
409 .collect(Collectors.toList());
410 }
411
412 @Override
413 public List<DeviceId> gatewayDeviceIds() {
Frank Wang894c7182017-06-02 15:49:08 +0800414 return gatewayNodes().stream().map(OpenstackNode::intBridge)
415 .collect(Collectors.toList());
daniel parke49eb382017-04-05 16:48:28 +0900416 }
417
418 private void updateGatewayGroup(OpenstackNode gatewayNode, boolean isInsert) {
419 nodeStore.values()
420 .stream()
421 .map(Versioned::value)
422 .filter(node -> node.type().equals(NodeType.COMPUTE))
daniel parkee8700b2017-05-11 15:50:03 +0900423 .filter(node -> node.dataIp().isPresent())
daniel parke49eb382017-04-05 16:48:28 +0900424 .filter(node -> node.state().equals(COMPLETE))
daniel parkee8700b2017-05-11 15:50:03 +0900425 .forEach(computeNode -> {
426 selectGroupHandler.updateGatewayGroupBuckets(computeNode,
427 ImmutableList.of(gatewayNode), NetworkMode.VXLAN, isInsert);
428 log.trace("Updated gateway group on {} for vxlan mode", computeNode.intBridge());
daniel parke49eb382017-04-05 16:48:28 +0900429 });
daniel parkee8700b2017-05-11 15:50:03 +0900430
431 nodeStore.values()
432 .stream()
433 .map(Versioned::value)
434 .filter(node -> node.type().equals(NodeType.COMPUTE))
435 .filter(node -> node.vlanPort().isPresent())
436 .filter(node -> node.state().equals(COMPLETE))
437 .forEach(computeNode -> {
438 selectGroupHandler.updateGatewayGroupBuckets(computeNode,
439 ImmutableList.of(gatewayNode), NetworkMode.VLAN, isInsert);
440 log.trace("Updated gateway group on {} for vlan mode", computeNode.intBridge());
441 });
442
daniel parke49eb382017-04-05 16:48:28 +0900443 }
444
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700445 private void initNode(OpenstackNode node) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700446 NodeState state = node.state();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700447 state.process(this, node);
448 log.debug("Processing node: {} state: {}", node.hostname(), state);
449 }
450
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700451 private void setNodeState(OpenstackNode node, NodeState newState) {
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900452 nodeStore.put(node.hostname(), getUpdatedNode(node, newState));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700453 }
454
455 private NodeState nodeState(OpenstackNode node) {
Frank Wang39b95772017-03-01 15:35:13 +0800456 if (!isOvsdbConnected(node) || !deviceService.isAvailable(node.intBridge()) ||
457 !isBridgeCreated(node.ovsdbId(), INTEGRATION_BRIDGE)) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700458 return INIT;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900459 }
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700460
461 // TODO use device service when we use single ONOS cluster for both openstackNode and vRouter
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700462 if (node.type().equals(NodeType.GATEWAY) &&
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700463 !isBridgeCreated(node.ovsdbId(), ROUTER_BRIDGE)) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700464 return INIT;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900465 }
466
daniel park917beb42017-03-16 18:07:15 +0900467 if (node.dataIp().isPresent() && !isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
468 return DEVICE_CREATED;
469 }
470
471 if (node.vlanPort().isPresent() && !isIfaceCreated(node.ovsdbId(), node.vlanPort().get())) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700472 return DEVICE_CREATED;
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700473 }
474
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700475 if (node.type().equals(NodeType.GATEWAY) && (
476 !isIfaceCreated(node.ovsdbId(), PATCH_ROUT_BRIDGE) ||
477 !isIfaceCreated(node.ovsdbId(), PATCH_INTG_BRIDGE) ||
478 !isIfaceCreated(node.ovsdbId(), node.uplink().get()))) {
479 return DEVICE_CREATED;
480 }
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700481 return COMPLETE;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900482 }
483
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700484 private boolean isIfaceCreated(DeviceId deviceId, String ifaceName) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700485 Device device = deviceService.getDevice(deviceId);
486 if (device == null || !device.is(BridgeConfig.class)) {
487 return false;
488 }
489
490 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
491 return bridgeConfig.getPorts().stream()
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900492 .anyMatch(port -> port.annotations().value(PORT_NAME).equals(ifaceName));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700493 }
494
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700495 private boolean isBridgeCreated(DeviceId deviceId, String bridgeName) {
496 Device device = deviceService.getDevice(deviceId);
497 if (device == null || !device.is(BridgeConfig.class)) {
498 return false;
499 }
500
501 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
502 return bridgeConfig.getBridges().stream()
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900503 .anyMatch(bridge -> bridge.name().equals(bridgeName));
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700504 }
505
506 private void createBridge(OpenstackNode node, String bridgeName, DeviceId deviceId) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700507 Device device = deviceService.getDevice(node.ovsdbId());
508 if (device == null || !device.is(BridgeConfig.class)) {
509 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900510 return;
511 }
512
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700513 // TODO fix this when we use single ONOS cluster for both openstackNode and vRouter
514 Set<IpAddress> controllerIps;
515 if (bridgeName.equals(ROUTER_BRIDGE)) {
516 controllerIps = Sets.newHashSet(node.routerController().get());
517 } else {
518 controllerIps = clusterService.getNodes().stream()
519 .map(ControllerNode::ip)
520 .collect(Collectors.toSet());
521 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900522
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700523 List<ControllerInfo> controllers = controllerIps.stream()
524 .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
525 .collect(Collectors.toList());
526
527 String dpid = deviceId.toString().substring(DPID_BEGIN);
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700528 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700529 .name(bridgeName)
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700530 .failMode(BridgeDescription.FailMode.SECURE)
531 .datapathId(dpid)
532 .disableInBand()
533 .controllers(controllers)
534 .build();
535
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700536 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700537 bridgeConfig.addBridge(bridgeDesc);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900538 }
539
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900540 private void createTunnelInterface(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700541 if (isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
542 return;
543 }
544
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700545 Device device = deviceService.getDevice(node.ovsdbId());
546 if (device == null || !device.is(InterfaceConfig.class)) {
547 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900548 return;
549 }
550
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700551 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
552 .deviceId(INTEGRATION_BRIDGE)
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700553 .ifaceName(DEFAULT_TUNNEL)
554 .type(VXLAN)
555 .remote(TunnelEndPoints.flowTunnelEndpoint())
556 .key(TunnelKeys.flowTunnelKey())
557 .build();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700558
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700559 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700560 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900561 }
562
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700563 private void createPatchInterface(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700564 checkArgument(node.type().equals(NodeType.GATEWAY));
565 if (isIfaceCreated(node.ovsdbId(), PATCH_INTG_BRIDGE) &&
566 isIfaceCreated(node.ovsdbId(), PATCH_ROUT_BRIDGE)) {
567 return;
568 }
569
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700570 Device device = deviceService.getDevice(node.ovsdbId());
571 if (device == null || !device.is(InterfaceConfig.class)) {
572 log.error("Failed to create patch interfaces on {}", node.hostname());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900573 return;
574 }
575
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700576 PatchDescription patchIntg = DefaultPatchDescription.builder()
577 .deviceId(INTEGRATION_BRIDGE)
578 .ifaceName(PATCH_INTG_BRIDGE)
579 .peer(PATCH_ROUT_BRIDGE)
580 .build();
581
582 PatchDescription patchRout = DefaultPatchDescription.builder()
583 .deviceId(ROUTER_BRIDGE)
584 .ifaceName(PATCH_ROUT_BRIDGE)
585 .peer(PATCH_INTG_BRIDGE)
586 .build();
587
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700588 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700589 ifaceConfig.addPatchMode(PATCH_INTG_BRIDGE, patchIntg);
590 ifaceConfig.addPatchMode(PATCH_ROUT_BRIDGE, patchRout);
591 }
592
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700593 private void addUplink(OpenstackNode node) {
594 checkArgument(node.type().equals(NodeType.GATEWAY));
595 if (isIfaceCreated(node.ovsdbId(), node.uplink().get())) {
596 return;
597 }
598
599 Device device = deviceService.getDevice(node.ovsdbId());
600 if (device == null || !device.is(BridgeConfig.class)) {
601 log.error("Failed to add port {} on {}", node.uplink().get(), node.ovsdbId());
602 return;
603 }
604
605 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
606 bridgeConfig.addPort(BridgeName.bridgeName(ROUTER_BRIDGE),
607 node.uplink().get());
608 }
609
daniel park917beb42017-03-16 18:07:15 +0900610 private void addVlanPort(OpenstackNode node) {
611 if (isIfaceCreated(node.ovsdbId(), node.vlanPort().get())) {
612 return;
613 }
614
615 Device device = deviceService.getDevice(node.ovsdbId());
616 if (device == null || !device.is(BridgeConfig.class)) {
617 log.error("Failed to add port {} on {}", node.vlanPort().get(), node.ovsdbId());
618 return;
619 }
620
621 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
622 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE),
623 node.vlanPort().get());
624 }
625
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700626 private boolean isOvsdbConnected(OpenstackNode node) {
627 OvsdbNodeId ovsdb = new OvsdbNodeId(node.managementIp(), ovsdbPort);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700628 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700629 return deviceService.isAvailable(node.ovsdbId()) &&
630 client != null &&
631 client.isConnected();
632 }
633
634 private void connectOvsdb(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700635 ovsdbController.connect(node.managementIp(), TpPort.tpPort(ovsdbPort));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700636 }
637
638 private Set<String> systemIfaces(OpenstackNode node) {
daniel park917beb42017-03-16 18:07:15 +0900639 Set<String> ifaces = Sets.newHashSet();
640 node.dataIp().ifPresent(ip -> ifaces.add(DEFAULT_TUNNEL));
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900641 node.vlanPort().ifPresent(ifaces::add);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700642 if (node.type().equals(NodeType.GATEWAY)) {
643 ifaces.add(PATCH_INTG_BRIDGE);
644 ifaces.add(PATCH_ROUT_BRIDGE);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700645 ifaces.add(node.uplink().get());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700646 }
647 return ifaces;
648 }
649
650 private OpenstackNode nodeByDeviceId(DeviceId deviceId) {
651 OpenstackNode node = nodes().stream()
652 .filter(n -> n.intBridge().equals(deviceId))
653 .findFirst().orElseGet(() -> nodes().stream()
654 .filter(n -> n.routerBridge().isPresent())
655 .filter(n -> n.routerBridge().get().equals(deviceId))
Frank Wang39b95772017-03-01 15:35:13 +0800656 .findFirst().orElseGet(() -> nodes().stream()
657 .filter(n -> n.ovsdbId().equals(deviceId))
658 .findFirst().orElse(null)));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700659 return node;
660 }
661
662 private class OvsdbHandler implements ConnectionHandler<Device> {
663
664 @Override
665 public void connected(Device device) {
666 OpenstackNode node = nodes().stream()
667 .filter(n -> n.ovsdbId().equals(device.id()))
668 .findFirst()
669 .orElse(null);
670 if (node != null) {
671 setNodeState(node, nodeState(node));
672 } else {
673 log.debug("{} is detected on unregistered node, ignore it.", device.id());
674 }
675 }
676
677 @Override
678 public void disconnected(Device device) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700679 OpenstackNode node = nodeByDeviceId(device.id());
680 if (node != null) {
681 log.warn("Device {} is disconnected", device.id());
682 setNodeState(node, NodeState.INCOMPLETE);
683 }
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700684 }
685 }
686
687 private class BridgeHandler implements ConnectionHandler<Device> {
688
689 @Override
690 public void connected(Device device) {
691 OpenstackNode node = nodeByDeviceId(device.id());
692 if (node != null) {
693 setNodeState(node, nodeState(node));
694 } else {
695 log.debug("{} is detected on unregistered node, ignore it.", device.id());
696 }
697 }
698
699 @Override
700 public void disconnected(Device device) {
701 OpenstackNode node = nodeByDeviceId(device.id());
702 if (node != null) {
703 log.warn("Device {} is disconnected", device.id());
704 setNodeState(node, NodeState.INCOMPLETE);
705 }
706 }
707
708 /**
709 * Handles port added situation.
710 * If the added port is tunnel or data plane interface, proceed to the remaining
711 * node initialization. Otherwise, do nothing.
712 *
713 * @param port port
714 */
715 public void portAdded(Port port) {
716 OpenstackNode node = nodeByDeviceId((DeviceId) port.element().id());
717 String portName = port.annotations().value(PORT_NAME);
718 if (node == null) {
719 log.debug("{} is added to unregistered node, ignore it.", portName);
720 return;
721 }
722
723 log.info("Port {} is added to {}", portName, node.hostname());
724 if (systemIfaces(node).contains(portName)) {
725 setNodeState(node, nodeState(node));
726 }
727 }
728
729 /**
730 * Handles port removed situation.
731 * If the removed port is tunnel or data plane interface, proceed to the remaining
732 * node initialization.Others, do nothing.
733 *
734 * @param port port
735 */
736 public void portRemoved(Port port) {
737 OpenstackNode node = nodeByDeviceId((DeviceId) port.element().id());
738 String portName = port.annotations().value(PORT_NAME);
739
740 if (node == null) {
741 return;
742 }
743
744 log.info("Port {} is removed from {}", portName, node.hostname());
745 if (systemIfaces(node).contains(portName)) {
746 setNodeState(node, NodeState.INCOMPLETE);
747 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900748 }
749 }
750
751 private class InternalDeviceListener implements DeviceListener {
752
753 @Override
754 public void event(DeviceEvent event) {
Daniel Parkad21c572016-03-09 10:18:24 +0900755
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700756 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
757 if (!Objects.equals(localNodeId, leaderNodeId)) {
758 // do not allow to proceed without leadership
Daniel Parkad21c572016-03-09 10:18:24 +0900759 return;
760 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900761
762 Device device = event.subject();
763 ConnectionHandler<Device> handler =
764 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
765
766 switch (event.type()) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700767 // TODO implement OVSDB port event so that we can handle updates on the OVSDB
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900768 case PORT_ADDED:
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700769 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900770 break;
771 case PORT_UPDATED:
772 if (!event.port().isEnabled()) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700773 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900774 }
775 break;
776 case DEVICE_ADDED:
777 case DEVICE_AVAILABILITY_CHANGED:
778 if (deviceService.isAvailable(device.id())) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700779 eventExecutor.execute(() -> handler.connected(device));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900780 } else {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700781 eventExecutor.execute(() -> handler.disconnected(device));
daniel parke49eb382017-04-05 16:48:28 +0900782 log.warn("OpenstackNode with device ID {} is disconnected", device.id());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900783 }
784 break;
785 default:
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900786 break;
787 }
788 }
789 }
790
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900791 private void readConfiguration() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700792 OpenstackNodeConfig config = configRegistry.getConfig(appId, CONFIG_CLASS);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900793 if (config == null) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700794 log.debug("No configuration found");
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900795 return;
796 }
sangho24556ec2016-08-25 10:41:14 +0900797
Hyunsun Moonbc672d62017-04-27 17:08:52 +0900798 Map<String, OpenstackNode> prevNodeMap = Maps.newHashMap(nodeStore.asJavaMap());
sangho24556ec2016-08-25 10:41:14 +0900799 config.openstackNodes().forEach(node -> {
800 prevNodeMap.remove(node.hostname());
801 addOrUpdateNode(node);
802 });
Sho SHIMIZU8ebb04a2016-10-06 15:58:29 -0700803 prevNodeMap.values().forEach(this::deleteNode);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900804 }
805
806 private class InternalConfigListener implements NetworkConfigListener {
807
808 @Override
809 public void event(NetworkConfigEvent event) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700810 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
811 if (!Objects.equals(localNodeId, leaderNodeId)) {
812 // do not allow to proceed without leadership
813 return;
814 }
815
816 if (!event.configClass().equals(CONFIG_CLASS)) {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900817 return;
818 }
819
820 switch (event.type()) {
821 case CONFIG_ADDED:
822 case CONFIG_UPDATED:
823 eventExecutor.execute(OpenstackNodeManager.this::readConfiguration);
824 break;
825 default:
826 break;
827 }
828 }
829 }
830
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700831 private class InternalMapListener implements MapEventListener<String, OpenstackNode> {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900832
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700833 @Override
834 public void event(MapEvent<String, OpenstackNode> event) {
835 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
836 if (!Objects.equals(localNodeId, leaderNodeId)) {
837 // do not allow to proceed without leadership
838 return;
839 }
840
841 OpenstackNode oldNode;
842 OpenstackNode newNode;
843
844 switch (event.type()) {
845 case UPDATE:
846 oldNode = event.oldValue().value();
847 newNode = event.newValue().value();
848
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700849 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700850 if (!newNode.equals(oldNode)) {
851 log.debug("New node: {}", newNode);
852 }
853 // performs init procedure even if the node is not changed
854 // for robustness since it's no harm to run init procedure
855 // multiple times
856 eventExecutor.execute(() -> initNode(newNode));
857 break;
858 case INSERT:
859 newNode = event.newValue().value();
860 log.info("Added {}", newNode.hostname());
861 eventExecutor.execute(() -> initNode(newNode));
862 break;
863 case REMOVE:
864 oldNode = event.oldValue().value();
865 log.info("Removed {}", oldNode.hostname());
866 break;
867 default:
868 break;
869 }
870 }
871 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900872}