blob: b19d78d517e6a7e1dab72f4e4a1b2c6982c504ef [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +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.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
27import org.onlab.packet.VlanId;
28import org.onlab.util.Tools;
29import org.onosproject.core.CoreService;
30import org.onosproject.mastership.MastershipService;
31import org.onosproject.net.ConnectPoint;
32import org.onosproject.net.DefaultAnnotations;
33import org.onosproject.net.Device;
34import org.onosproject.net.Host;
35import org.onosproject.net.HostId;
36import org.onosproject.net.HostLocation;
37import org.onosproject.net.Port;
38import org.onosproject.net.device.DeviceEvent;
39import org.onosproject.net.device.DeviceListener;
40import org.onosproject.net.device.DeviceService;
41import org.onosproject.net.host.DefaultHostDescription;
42import org.onosproject.net.host.HostDescription;
43import org.onosproject.net.host.HostProvider;
44import org.onosproject.net.host.HostProviderRegistry;
45import org.onosproject.net.host.HostProviderService;
46import org.onosproject.net.host.HostService;
47import org.onosproject.net.provider.AbstractProvider;
48import org.onosproject.net.provider.ProviderId;
Jian Liec5c32b2018-07-13 14:28:58 +090049import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090051import org.onosproject.openstacknode.api.OpenstackNode;
52import org.onosproject.openstacknode.api.OpenstackNodeEvent;
53import org.onosproject.openstacknode.api.OpenstackNodeListener;
54import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.openstack4j.model.network.Network;
daniel park796c2eb2018-03-22 17:01:51 +090056import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090057import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
Jian Liec5c32b2018-07-13 14:28:58 +090060import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import java.util.Set;
62import java.util.concurrent.ExecutorService;
63import java.util.concurrent.Executors;
64import java.util.stream.Collectors;
65
66import static org.onlab.util.Tools.groupedThreads;
67import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Jian Liec5c32b2018-07-13 14:28:58 +090068import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_CREATE_TIME;
69import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_NETWORK_ID;
70import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_PORT_ID;
71import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_SEGMENT_ID;
daniel park796c2eb2018-03-22 17:01:51 +090072import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Ray Milkey9dc57392018-06-08 08:52:31 -070073import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
Jian Li51b844c2018-05-31 10:59:03 +090074import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075
76@Service
77@Component(immediate = true)
Jian Li46b74002018-07-15 18:39:08 +090078public final class OpenstackSwitchingHostProvider
79 extends AbstractProvider implements HostProvider {
Hyunsun Moon44aac662017-02-18 02:07:01 +090080
81 private final Logger log = LoggerFactory.getLogger(getClass());
82
83 private static final String PORT_NAME_PREFIX_VM = "tap";
84 private static final String ERR_ADD_HOST = "Failed to add host: ";
Jian Li9d676fb2018-03-02 15:25:36 +090085 private static final String SONA_HOST_SCHEME = "sona";
Hyunsun Moon44aac662017-02-18 02:07:01 +090086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d676fb2018-03-02 15:25:36 +090088 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090089
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d676fb2018-03-02 15:25:36 +090091 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d676fb2018-03-02 15:25:36 +090094 protected HostProviderRegistry hostProviderRegistry;
Hyunsun Moon44aac662017-02-18 02:07:01 +090095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d676fb2018-03-02 15:25:36 +090097 protected HostService hostService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090098
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d676fb2018-03-02 15:25:36 +0900100 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d676fb2018-03-02 15:25:36 +0900103 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d676fb2018-03-02 15:25:36 +0900106 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900107
Jian Li24ec59f2018-05-23 19:01:25 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liec5c32b2018-07-13 14:28:58 +0900109 protected InstancePortAdminService instancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +0900110
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111 private final ExecutorService deviceEventExecutor =
Jian Li46b74002018-07-15 18:39:08 +0900112 Executors.newSingleThreadExecutor(groupedThreads(this.getClass().getSimpleName(), "device-event"));
113 private final InternalDeviceListener internalDeviceListener =
114 new InternalDeviceListener();
115 private final InternalOpenstackNodeListener internalNodeListener =
116 new InternalOpenstackNodeListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900117
118 private HostProviderService hostProvider;
119
120 /**
121 * Creates OpenStack switching host provider.
122 */
123 public OpenstackSwitchingHostProvider() {
Jian Li9d676fb2018-03-02 15:25:36 +0900124 super(new ProviderId(SONA_HOST_SCHEME, OPENSTACK_NETWORKING_APP_ID));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125 }
126
127 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800128 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129 coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
130 deviceService.addListener(internalDeviceListener);
131 osNodeService.addListener(internalNodeListener);
132 hostProvider = hostProviderRegistry.register(this);
133
134 log.info("Started");
135 }
136
137 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800138 void deactivate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 hostProviderRegistry.unregister(this);
140 osNodeService.removeListener(internalNodeListener);
141 deviceService.removeListener(internalDeviceListener);
142
143 deviceEventExecutor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144
145 log.info("Stopped");
146 }
147
148 @Override
149 public void triggerProbe(Host host) {
150 // no probe is required
151 }
152
Jian Li9d676fb2018-03-02 15:25:36 +0900153 /**
154 * Processes port addition event.
155 * Once a port addition event is detected, it tries to create a host instance
156 * with openstack augmented host information such as networkId, portId,
157 * createTime, segmentId and notifies to host provider.
158 *
159 * @param port port object used in ONOS
160 */
Jian Li24ec59f2018-05-23 19:01:25 +0900161 private void processPortAdded(Port port, Device device) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 // TODO check the node state is COMPLETE
163 org.openstack4j.model.network.Port osPort = osNetworkService.port(port);
164 if (osPort == null) {
165 log.warn(ERR_ADD_HOST + "OpenStack port for {} not found", port);
166 return;
167 }
168
169 Network osNet = osNetworkService.network(osPort.getNetworkId());
170 if (osNet == null) {
171 log.warn(ERR_ADD_HOST + "OpenStack network {} not found",
172 osPort.getNetworkId());
173 return;
174 }
175
176 if (osPort.getFixedIps().isEmpty()) {
177 log.warn(ERR_ADD_HOST + "no fixed IP for port {}", osPort.getId());
178 return;
179 }
180
Jian Liec5c32b2018-07-13 14:28:58 +0900181 MacAddress mac = MacAddress.valueOf(osPort.getMacAddress());
182 HostId hostId = HostId.hostId(mac);
183
184 // typically one openstack port should only be bound to one fix IP address;
185 // however, openstack4j binds multiple fixed IPs to one port, this might
186 // be a defect of openstack4j implementation
187
188 // TODO: we need to find a way to bind multiple ports from multiple
189 // openstack networks into one host sooner or later
Hyunsun Moon44aac662017-02-18 02:07:01 +0900190 Set<IpAddress> fixedIps = osPort.getFixedIps().stream()
Jian Li46b74002018-07-15 18:39:08 +0900191 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
192 .collect(Collectors.toSet());
Jian Liec5c32b2018-07-13 14:28:58 +0900193
194 // connect point is the combination of switch ID with port number where
195 // the host is attached to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900196 ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
Jian Li24ec59f2018-05-23 19:01:25 +0900197
Jian Liec5c32b2018-07-13 14:28:58 +0900198 long createTime = System.currentTimeMillis();
Jian Li24ec59f2018-05-23 19:01:25 +0900199
Jian Liee8214a2018-07-21 20:07:28 +0900200 // we check whether the host already attached to same locations
Jian Liec5c32b2018-07-13 14:28:58 +0900201 Host host = hostService.getHost(hostId);
Jian Li46b74002018-07-15 18:39:08 +0900202
203 // build host annotations to include a set of meta info from neutron
204 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
205 .set(ANNOTATION_NETWORK_ID, osPort.getNetworkId())
206 .set(ANNOTATION_PORT_ID, osPort.getId())
207 .set(ANNOTATION_CREATE_TIME, String.valueOf(createTime));
208
Jian Liee8214a2018-07-21 20:07:28 +0900209 // FLAT typed network does not require segment ID
Jian Li46b74002018-07-15 18:39:08 +0900210 if (osNet.getNetworkType() != NetworkType.FLAT) {
211 annotations.set(ANNOTATION_SEGMENT_ID, osNet.getProviderSegID());
212 }
213
214 // build host description object
215 HostDescription hostDesc = new DefaultHostDescription(
216 mac,
217 VlanId.NONE,
218 new HostLocation(connectPoint, createTime),
219 fixedIps,
220 annotations.build());
221
Jian Liec5c32b2018-07-13 14:28:58 +0900222 if (host != null) {
223 Set<HostLocation> locations = host.locations().stream()
224 .filter(l -> l.deviceId().equals(connectPoint.deviceId()))
225 .filter(l -> l.port().equals(connectPoint.port()))
226 .collect(Collectors.toSet());
Jian Li46b74002018-07-15 18:39:08 +0900227
228 // newly added location is not in the existing location list,
229 // therefore, we simply add this into the location list
Jian Liec5c32b2018-07-13 14:28:58 +0900230 if (locations.size() == 0) {
231 hostProvider.addLocationToHost(hostId,
Jian Li46b74002018-07-15 18:39:08 +0900232 new HostLocation(connectPoint, createTime));
233 }
234
235 // newly added location is in the existing location list,
236 // the hostDetected method invocation in turn triggers host Update event
237 if (locations.size() == 1) {
238 hostProvider.hostDetected(hostId, hostDesc, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900239 }
Jian Liec5c32b2018-07-13 14:28:58 +0900240 } else {
Jian Liec5c32b2018-07-13 14:28:58 +0900241 hostProvider.hostDetected(hostId, hostDesc, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900242 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900243 }
244
Jian Li9d676fb2018-03-02 15:25:36 +0900245 /**
246 * Processes port removal event.
247 * Once a port removal event is detected, it tries to look for a host
248 * instance through host provider by giving connect point information,
249 * and vanishes it.
250 *
Jian Li24ec59f2018-05-23 19:01:25 +0900251 * @param event device event
Jian Li9d676fb2018-03-02 15:25:36 +0900252 */
Jian Li24ec59f2018-05-23 19:01:25 +0900253 private void processPortRemoved(DeviceEvent event) {
254 Port port = event.port();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900255 ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
Jian Li24ec59f2018-05-23 19:01:25 +0900256
Jian Liec5c32b2018-07-13 14:28:58 +0900257 Set<Host> hosts = hostService.getConnectedHosts(connectPoint);
Jian Li24ec59f2018-05-23 19:01:25 +0900258
Jian Liec5c32b2018-07-13 14:28:58 +0900259 hosts.forEach(h -> {
260 Optional<HostLocation> hostLocation = h.locations().stream()
261 .filter(l -> l.deviceId().equals(port.element().id()))
262 .filter(l -> l.port().equals(port.number())).findAny();
Jian Li24ec59f2018-05-23 19:01:25 +0900263
Jian Liec5c32b2018-07-13 14:28:58 +0900264 // if the host contains only one filtered location, we remove the host
265 if (h.locations().size() == 1) {
266 hostProvider.hostVanished(h.id());
Jian Li24ec59f2018-05-23 19:01:25 +0900267 }
268
Jian Liec5c32b2018-07-13 14:28:58 +0900269 // if the host contains multiple locations, we simply remove the
270 // host location
271 if (h.locations().size() > 1 && hostLocation.isPresent()) {
272 hostProvider.removeLocationFromHost(h.id(), hostLocation.get());
273 }
274 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900275 }
276
Jian Li9d676fb2018-03-02 15:25:36 +0900277 /**
278 * An internal device listener which listens the port events generated from
279 * OVS integration bridge.
280 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900281 private class InternalDeviceListener implements DeviceListener {
282
283 @Override
284 public boolean isRelevant(DeviceEvent event) {
285 Device device = event.subject();
286 if (!mastershipService.isLocalMaster(device.id())) {
287 // do not allow to proceed without mastership
288 return false;
289 }
290 Port port = event.port();
291 if (port == null) {
292 return false;
293 }
294 String portName = port.annotations().value(PORT_NAME);
Jian Li9d676fb2018-03-02 15:25:36 +0900295
296 return !Strings.isNullOrEmpty(portName) &&
Daniel Parkc4d06402018-05-28 15:57:37 +0900297 (portName.startsWith(PORT_NAME_PREFIX_VM) || isDirectPort(portName));
298 }
299
300 private boolean isDirectPort(String portName) {
Ray Milkey9dc57392018-06-08 08:52:31 -0700301 return portNamePrefixMap().values().stream().filter(p -> portName.startsWith(p)).findAny().isPresent();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900302 }
303
304 @Override
305 public void event(DeviceEvent event) {
Daniel Parkc4d06402018-05-28 15:57:37 +0900306 log.info("Device event occurred with type {}", event.type());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900307 switch (event.type()) {
308 case PORT_UPDATED:
309 if (!event.port().isEnabled()) {
Jian Li9d676fb2018-03-02 15:25:36 +0900310 portRemovedHelper(deviceEventExecutor, event);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311 } else if (event.port().isEnabled()) {
Jian Li9d676fb2018-03-02 15:25:36 +0900312 portAddedHelper(deviceEventExecutor, event);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900313 }
314 break;
315 case PORT_ADDED:
Jian Li9d676fb2018-03-02 15:25:36 +0900316 portAddedHelper(deviceEventExecutor, event);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900317 break;
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900318 case PORT_REMOVED:
Jian Li9d676fb2018-03-02 15:25:36 +0900319 portRemovedHelper(deviceEventExecutor, event);
Ray Milkeyd6a67c32018-02-02 10:30:35 -0800320 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900321 default:
322 break;
323 }
324 }
325 }
326
Jian Li9d676fb2018-03-02 15:25:36 +0900327 /**
328 * A helper method which logs the port addition event and performs port
329 * addition action.
330 *
331 * @param executor device executor service
332 * @param event device event
333 */
334 private void portAddedHelper(ExecutorService executor, DeviceEvent event) {
335 executor.execute(() -> {
336 log.debug("Instance port {} is detected from {}",
337 event.port().annotations().value(PORT_NAME),
338 event.subject().id());
Jian Li24ec59f2018-05-23 19:01:25 +0900339 processPortAdded(event.port(), event.subject());
Jian Li9d676fb2018-03-02 15:25:36 +0900340 });
341 }
342
343 /**
344 * A helper method which logs the port removal event and performs port
345 * removal action.
346 *
347 * @param executor device executor service
348 * @param event device event
349 */
350 private void portRemovedHelper(ExecutorService executor, DeviceEvent event) {
351 executor.execute(() -> {
352 log.debug("Instance port {} is removed from {}",
353 event.port().annotations().value(PORT_NAME),
354 event.subject().id());
Jian Li24ec59f2018-05-23 19:01:25 +0900355 processPortRemoved(event);
Jian Li9d676fb2018-03-02 15:25:36 +0900356 });
357 }
358
Hyunsun Moon44aac662017-02-18 02:07:01 +0900359 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
360
361 @Override
Jian Li9d676fb2018-03-02 15:25:36 +0900362 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li51b844c2018-05-31 10:59:03 +0900363
364 if (event.subject().type() == CONTROLLER) {
365 return false;
366 }
Jian Li9d676fb2018-03-02 15:25:36 +0900367 // do not allow to proceed without mastership
368 Device device = deviceService.getDevice(event.subject().intgBridge());
Jian Li7ddea782018-03-30 11:17:42 +0900369 if (device == null) {
370 return false;
371 }
Jian Li9d676fb2018-03-02 15:25:36 +0900372 return mastershipService.isLocalMaster(device.id());
373 }
374
375 @Override
Hyunsun Moon44aac662017-02-18 02:07:01 +0900376 public void event(OpenstackNodeEvent event) {
377 OpenstackNode osNode = event.subject();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900378
379 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900380 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900381 deviceEventExecutor.execute(() -> {
382 log.info("COMPLETE node {} is detected", osNode.hostname());
383 processCompleteNode(event.subject());
384 });
385 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900386 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900387 log.warn("{} is changed to INCOMPLETE state", osNode);
388 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900389 case OPENSTACK_NODE_CREATED:
390 case OPENSTACK_NODE_UPDATED:
391 case OPENSTACK_NODE_REMOVED:
Jian Li9d676fb2018-03-02 15:25:36 +0900392 // not reacts to the events other than complete and incomplete states
393 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900394 default:
395 break;
396 }
397 }
398
399 private void processCompleteNode(OpenstackNode osNode) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900400 deviceService.getPorts(osNode.intgBridge()).stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900401 .filter(port -> port.annotations().value(PORT_NAME)
402 .startsWith(PORT_NAME_PREFIX_VM) &&
403 port.isEnabled())
404 .forEach(port -> {
405 log.debug("Instance port {} is detected from {}",
Jian Li46b74002018-07-15 18:39:08 +0900406 port.annotations().value(PORT_NAME),
407 osNode.hostname());
Jian Li24ec59f2018-05-23 19:01:25 +0900408 processPortAdded(port,
409 deviceService.getDevice(osNode.intgBridge()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900410 });
411
Ray Milkey9dc57392018-06-08 08:52:31 -0700412 portNamePrefixMap().values().forEach(portNamePrefix -> {
Daniel Parkc4d06402018-05-28 15:57:37 +0900413 deviceService.getPorts(osNode.intgBridge()).stream()
414 .filter(port -> port.annotations().value(PORT_NAME)
415 .startsWith(portNamePrefix) &&
416 port.isEnabled())
417 .forEach(port -> {
418 log.debug("Instance port {} is detected from {}",
419 port.annotations().value(portNamePrefix),
420 osNode.hostname());
Jian Li24ec59f2018-05-23 19:01:25 +0900421 processPortAdded(port,
422 deviceService.getDevice(osNode.intgBridge()));
Daniel Parkc4d06402018-05-28 15:57:37 +0900423 });
424 });
425
Hyunsun Moon44aac662017-02-18 02:07:01 +0900426 Tools.stream(hostService.getHosts())
427 .filter(host -> deviceService.getPort(
428 host.location().deviceId(),
429 host.location().port()) == null)
430 .forEach(host -> {
431 log.info("Remove stale host {}", host.id());
432 hostProvider.hostVanished(host.id());
Jian Li46b74002018-07-15 18:39:08 +0900433 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900434 }
435 }
436}