Add DiscoveryPlugin interface

So we have a Pull interface easier to use which reduce the need of Guice.

See 2a9d7f68a1 (commitcomment-18335161)
This commit is contained in:
David Pilato 2016-07-21 11:35:29 +02:00
parent 2a9d7f68a1
commit 5e57febe53
13 changed files with 128 additions and 49 deletions

View File

@ -54,6 +54,7 @@ import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.internal.InternalSettingsPreparer;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.DiscoveryPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.plugins.SearchPlugin;
@ -122,7 +123,7 @@ public abstract class TransportClient extends AbstractClient {
for (Module pluginModule : pluginsService.createGuiceModules()) {
modules.add(pluginModule);
}
modules.add(new NetworkModule(networkService, settings, true, namedWriteableRegistry));
modules.add(new NetworkModule(networkService, settings, true, namedWriteableRegistry, pluginsService.filterPlugins(DiscoveryPlugin.class)));
modules.add(b -> b.bind(ThreadPool.class).toInstance(threadPool));
modules.add(new SearchModule(settings, namedWriteableRegistry, true, pluginsService.filterPlugins(SearchPlugin.class)));
ActionModule actionModule = new ActionModule(false, true, settings, null, settingsModule.getClusterSettings(),

View File

@ -20,7 +20,6 @@
package org.elasticsearch.common.network;
import org.elasticsearch.action.support.replication.ReplicationTask;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.routing.allocation.command.AllocateEmptyPrimaryAllocationCommand;
import org.elasticsearch.cluster.routing.allocation.command.AllocateReplicaAllocationCommand;
import org.elasticsearch.cluster.routing.allocation.command.AllocateStalePrimaryAllocationCommand;
@ -39,6 +38,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.ExtensionPoint;
import org.elasticsearch.http.HttpServer;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.plugins.DiscoveryPlugin;
import org.elasticsearch.tasks.RawTaskStatus;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.transport.Transport;
@ -46,6 +46,7 @@ import org.elasticsearch.transport.TransportService;
import org.elasticsearch.transport.local.LocalTransport;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@ -78,13 +79,14 @@ public class NetworkModule extends AbstractModule {
/**
* Creates a network module that custom networking classes can be plugged into.
*
* @param networkService A constructed network service object to bind.
* @param networkService A constructed network service object to bind.
* @param settings The settings for the node
* @param transportClient True if only transport classes should be allowed to be registered, false otherwise.
* @param namedWriteableRegistry registry for named writeables for use during streaming
* @param discoveryPlugins Discovery plugins
*/
public NetworkModule(NetworkService networkService, Settings settings, boolean transportClient, NamedWriteableRegistry namedWriteableRegistry) {
public NetworkModule(NetworkService networkService, Settings settings, boolean transportClient,
NamedWriteableRegistry namedWriteableRegistry, List<DiscoveryPlugin> discoveryPlugins) {
this.networkService = networkService;
this.settings = settings;
this.transportClient = transportClient;
@ -94,6 +96,7 @@ public class NetworkModule extends AbstractModule {
registerTaskStatus(ReplicationTask.Status.NAME, ReplicationTask.Status::new);
registerTaskStatus(RawTaskStatus.NAME, RawTaskStatus::new);
registerBuiltinAllocationCommands();
registerCustomNameResolvers(discoveryPlugins);
}
public boolean isTransportClient() {
@ -139,6 +142,18 @@ public class NetworkModule extends AbstractModule {
namedWriteableRegistry.register(AllocationCommand.class, commandName.getPreferredName(), reader);
}
/**
* Register custom name resolver a DiscoveryPlugin might provide
* @param discoveryPlugins Discovery plugins
*/
private void registerCustomNameResolvers(List<DiscoveryPlugin> discoveryPlugins) {
for (DiscoveryPlugin discoveryPlugin : discoveryPlugins) {
NetworkService.CustomNameResolver customNameResolver = discoveryPlugin.getCustomNameResolver(settings);
if (customNameResolver != null) {
this.networkService.addCustomNameResolver(customNameResolver);
}
}
}
/**
* The registry of allocation command parsers.
*/
@ -146,18 +161,8 @@ public class NetworkModule extends AbstractModule {
return allocationCommandRegistry;
}
private final List<NetworkService.CustomNameResolver> customNameResolvers = new CopyOnWriteArrayList<>();
/**
* Add a custom name resolver.
*/
public void addCustomNameResolver(NetworkService.CustomNameResolver customNameResolver) {
customNameResolvers.add(customNameResolver);
}
@Override
protected void configure() {
networkService.setCustomNameResolvers(customNameResolvers);
bind(NetworkService.class).toInstance(networkService);
bind(NamedWriteableRegistry.class).toInstance(namedWriteableRegistry);
transportServiceTypes.bindType(binder(), settings, TRANSPORT_SERVICE_TYPE_KEY, "default");

View File

@ -90,15 +90,15 @@ public class NetworkService extends AbstractComponent {
InetAddress[] resolveIfPossible(String value) throws IOException;
}
private List<CustomNameResolver> customNameResolvers;
private final List<CustomNameResolver> customNameResolvers = new CopyOnWriteArrayList<>();;
public NetworkService(Settings settings) {
super(settings);
IfConfig.logIfNecessary();
}
public void setCustomNameResolvers(List<CustomNameResolver> customNameResolvers) {
this.customNameResolvers = customNameResolvers;
public void addCustomNameResolver(CustomNameResolver customNameResolver) {
this.customNameResolvers.add(customNameResolver);
}
/**

View File

@ -92,6 +92,7 @@ import org.elasticsearch.node.internal.InternalSettingsPreparer;
import org.elasticsearch.node.service.NodeService;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.AnalysisPlugin;
import org.elasticsearch.plugins.DiscoveryPlugin;
import org.elasticsearch.plugins.IngestPlugin;
import org.elasticsearch.plugins.MapperPlugin;
import org.elasticsearch.plugins.Plugin;
@ -280,7 +281,8 @@ public class Node implements Closeable {
}
final MonitorService monitorService = new MonitorService(settings, nodeEnvironment, threadPool);
modules.add(new NodeModule(this, monitorService));
modules.add(new NetworkModule(networkService, settings, false, namedWriteableRegistry));
modules.add(new NetworkModule(networkService, settings, false, namedWriteableRegistry,
pluginsService.filterPlugins(DiscoveryPlugin.class)));
modules.add(new DiscoveryModule(this.settings));
ClusterModule clusterModule = new ClusterModule(settings, clusterService);
modules.add(clusterModule);

View File

@ -0,0 +1,58 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.plugins;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.CharFilter;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.Tokenizer;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.analysis.AnalyzerProvider;
import org.elasticsearch.index.analysis.CharFilterFactory;
import org.elasticsearch.index.analysis.TokenFilterFactory;
import org.elasticsearch.index.analysis.TokenizerFactory;
import org.elasticsearch.indices.analysis.AnalysisModule.AnalysisProvider;
import java.util.Map;
import static java.util.Collections.emptyMap;
/**
* An additional extension point for {@link Plugin}s that extends Elasticsearch's discovery functionality. To add an additional
* {@link NetworkService.CustomNameResolver} just implement the interface and implement the {@link #getCustomNameResolver(Settings)} method:
*
* <pre>{@code
* public class MyDiscoveryPlugin extends Plugin implements DiscoveryPlugin {
* &#64;Override
* public NetworkService.CustomNameResolver getCustomNameResolver(Settings settings) {
* return new YourCustomNameResolverInstance(settings);
* }
* }
* }</pre>
*/
public interface DiscoveryPlugin {
/**
* Override to add additional {@link NetworkService.CustomNameResolver}s.
*/
default NetworkService.CustomNameResolver getCustomNameResolver(Settings settings) {
return null;
}
}

View File

@ -45,12 +45,12 @@ import org.elasticsearch.test.rest.FakeRestRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import static java.util.Collections.emptyMap;
import static java.util.Collections.unmodifiableList;
import static org.elasticsearch.common.unit.TimeValue.timeValueMillis;
@ -75,7 +75,8 @@ public class ClusterRerouteRequestTests extends ESTestCase {
public ClusterRerouteRequestTests() {
namedWriteableRegistry = new NamedWriteableRegistry();
allocationCommandRegistry = new NetworkModule(null, null, true, namedWriteableRegistry).getAllocationCommandRegistry();
allocationCommandRegistry = new NetworkModule(null, null, true, namedWriteableRegistry, Collections.emptyList())
.getAllocationCommandRegistry();
}
private ClusterRerouteRequest randomRequest() {

View File

@ -65,7 +65,7 @@ public class ClusterRerouteTests extends ESAllocationTestCase {
req.writeTo(out);
BytesReference bytes = out.bytes();
NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry();
new NetworkModule(null, Settings.EMPTY, true, namedWriteableRegistry);
new NetworkModule(null, Settings.EMPTY, true, namedWriteableRegistry, Collections.emptyList());
StreamInput wrap = new NamedWriteableAwareStreamInput(bytes.streamInput(),
namedWriteableRegistry);
ClusterRerouteRequest deserializedReq = new ClusterRerouteRequest();

View File

@ -51,8 +51,11 @@ import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.shard.ShardNotFoundException;
import org.elasticsearch.plugins.DiscoveryPlugin;
import org.elasticsearch.test.ESAllocationTestCase;
import java.util.Collections;
import static java.util.Collections.singleton;
import static org.elasticsearch.cluster.routing.ShardRoutingState.INITIALIZING;
import static org.elasticsearch.cluster.routing.ShardRoutingState.RELOCATING;
@ -434,7 +437,7 @@ public class AllocationCommandsTests extends ESAllocationTestCase {
// Since the commands are named writeable we need to register them and wrap the input stream
NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry();
new NetworkModule(null, Settings.EMPTY, true, namedWriteableRegistry);
new NetworkModule(null, Settings.EMPTY, true, namedWriteableRegistry, Collections.emptyList());
in = new NamedWriteableAwareStreamInput(in, namedWriteableRegistry);
// Now we can read them!
@ -480,8 +483,8 @@ public class AllocationCommandsTests extends ESAllocationTestCase {
// move two tokens, parser expected to be "on" `commands` field
parser.nextToken();
parser.nextToken();
AllocationCommandRegistry registry = new NetworkModule(null, Settings.EMPTY, true, new NamedWriteableRegistry())
.getAllocationCommandRegistry();
AllocationCommandRegistry registry = new NetworkModule(null, Settings.EMPTY, true, new NamedWriteableRegistry(),
Collections.emptyList()).getAllocationCommandRegistry();
AllocationCommands sCommands = AllocationCommands.fromXContent(parser, ParseFieldMatcher.STRICT, registry);
assertThat(sCommands.commands().size(), equalTo(5));

View File

@ -44,6 +44,7 @@ import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportService;
import java.io.IOException;
import java.util.Collections;
public class NetworkModuleTests extends ModuleTestCase {
@ -112,13 +113,14 @@ public class NetworkModuleTests extends ModuleTestCase {
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
.put(NetworkModule.TRANSPORT_TYPE_KEY, "local")
.build();
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry());
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry(),
Collections.emptyList());
module.registerTransportService("custom", FakeTransportService.class);
assertBinding(module, TransportService.class, FakeTransportService.class);
assertFalse(module.isTransportClient());
// check it works with transport only as well
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry());
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry(), Collections.emptyList());
module.registerTransportService("custom", FakeTransportService.class);
assertBinding(module, TransportService.class, FakeTransportService.class);
assertTrue(module.isTransportClient());
@ -128,13 +130,14 @@ public class NetworkModuleTests extends ModuleTestCase {
Settings settings = Settings.builder().put(NetworkModule.TRANSPORT_TYPE_KEY, "custom")
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
.build();
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry());
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry(),
Collections.emptyList());
module.registerTransport("custom", FakeTransport.class);
assertBinding(module, Transport.class, FakeTransport.class);
assertFalse(module.isTransportClient());
// check it works with transport only as well
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry());
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry(), Collections.emptyList());
module.registerTransport("custom", FakeTransport.class);
assertBinding(module, Transport.class, FakeTransport.class);
assertTrue(module.isTransportClient());
@ -144,13 +147,14 @@ public class NetworkModuleTests extends ModuleTestCase {
Settings settings = Settings.builder()
.put(NetworkModule.HTTP_TYPE_SETTING.getKey(), "custom")
.put(NetworkModule.TRANSPORT_TYPE_KEY, "local").build();
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry());
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry(),
Collections.emptyList());
module.registerHttpTransport("custom", FakeHttpTransport.class);
assertBinding(module, HttpServerTransport.class, FakeHttpTransport.class);
assertFalse(module.isTransportClient());
// check registration not allowed for transport only
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry());
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry(), Collections.emptyList());
assertTrue(module.isTransportClient());
try {
module.registerHttpTransport("custom", FakeHttpTransport.class);
@ -163,7 +167,7 @@ public class NetworkModuleTests extends ModuleTestCase {
// not added if http is disabled
settings = Settings.builder().put(NetworkModule.HTTP_ENABLED.getKey(), false)
.put(NetworkModule.TRANSPORT_TYPE_KEY, "local").build();
module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry());
module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry(), Collections.emptyList());
assertNotBound(module, HttpServerTransport.class);
assertFalse(module.isTransportClient());
}
@ -171,7 +175,7 @@ public class NetworkModuleTests extends ModuleTestCase {
public void testRegisterTaskStatus() {
NamedWriteableRegistry registry = new NamedWriteableRegistry();
Settings settings = Settings.EMPTY;
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, registry);
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, registry, Collections.emptyList());
assertFalse(module.isTransportClient());
// Builtin reader comes back

View File

@ -44,18 +44,20 @@ import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.discovery.DiscoveryModule;
import org.elasticsearch.discovery.ec2.AwsEc2UnicastHostsProvider;
import org.elasticsearch.discovery.zen.ZenDiscovery;
import org.elasticsearch.node.Node;
import org.elasticsearch.plugins.DiscoveryPlugin;
import org.elasticsearch.plugins.Plugin;
/**
*
*/
public class Ec2DiscoveryPlugin extends Plugin {
public class Ec2DiscoveryPlugin extends Plugin implements DiscoveryPlugin {
private static ESLogger logger = Loggers.getLogger(Ec2DiscoveryPlugin.class);
@ -107,9 +109,10 @@ public class Ec2DiscoveryPlugin extends Plugin {
discoveryModule.addUnicastHostProvider(EC2, AwsEc2UnicastHostsProvider.class);
}
public void onModule(NetworkModule networkModule) {
@Override
public NetworkService.CustomNameResolver getCustomNameResolver(Settings settings) {
logger.debug("Register _ec2_, _ec2:xxx_ network names");
networkModule.addCustomNameResolver(new Ec2NameResolver(settings));
return new Ec2NameResolver(settings);
}
@Override

View File

@ -26,7 +26,6 @@ import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Collections;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString;
@ -44,7 +43,7 @@ public class Ec2NetworkTests extends ESTestCase {
.build();
NetworkService networkService = new NetworkService(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new Ec2NameResolver(nodeSettings)));
networkService.addCustomNameResolver(new Ec2NameResolver(nodeSettings));
// TODO we need to replace that with a mock. For now we check the URL we are supposed to reach.
try {
networkService.resolveBindHostAddresses(null);
@ -62,7 +61,7 @@ public class Ec2NetworkTests extends ESTestCase {
.build();
NetworkService networkService = new NetworkService(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new Ec2NameResolver(nodeSettings)));
networkService.addCustomNameResolver(new Ec2NameResolver(nodeSettings));
// TODO we need to replace that with a mock. For now we check the URL we are supposed to reach.
try {
networkService.resolveBindHostAddresses(null);
@ -80,7 +79,7 @@ public class Ec2NetworkTests extends ESTestCase {
.build();
NetworkService networkService = new NetworkService(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new Ec2NameResolver(nodeSettings)));
networkService.addCustomNameResolver(new Ec2NameResolver(nodeSettings));
// TODO we need to replace that with a mock. For now we check the URL we are supposed to reach.
try {
networkService.resolveBindHostAddresses(null);
@ -98,7 +97,7 @@ public class Ec2NetworkTests extends ESTestCase {
.build();
NetworkService networkService = new NetworkService(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new Ec2NameResolver(nodeSettings)));
networkService.addCustomNameResolver(new Ec2NameResolver(nodeSettings));
// TODO we need to replace that with a mock. For now we check the URL we are supposed to reach.
try {
networkService.resolveBindHostAddresses(null);
@ -116,7 +115,7 @@ public class Ec2NetworkTests extends ESTestCase {
.build();
NetworkService networkService = new NetworkService(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new Ec2NameResolver(nodeSettings)));
networkService.addCustomNameResolver(new Ec2NameResolver(nodeSettings));
// TODO we need to replace that with a mock. For now we check the URL we are supposed to reach.
try {
networkService.resolveBindHostAddresses(null);
@ -134,7 +133,7 @@ public class Ec2NetworkTests extends ESTestCase {
.build();
NetworkService networkService = new NetworkService(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new Ec2NameResolver(nodeSettings)));
networkService.addCustomNameResolver(new Ec2NameResolver(nodeSettings));
// TODO we need to replace that with a mock. For now we check the URL we are supposed to reach.
try {
networkService.resolveBindHostAddresses(null);
@ -152,7 +151,7 @@ public class Ec2NetworkTests extends ESTestCase {
.build();
NetworkService networkService = new NetworkService(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new Ec2NameResolver(nodeSettings)));
networkService.addCustomNameResolver(new Ec2NameResolver(nodeSettings));
// TODO we need to replace that with a mock. For now we check the URL we are supposed to reach.
try {
networkService.resolveBindHostAddresses(null);
@ -171,7 +170,7 @@ public class Ec2NetworkTests extends ESTestCase {
.build();
NetworkService networkService = new NetworkService(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new Ec2NameResolver(nodeSettings)));
networkService.addCustomNameResolver(new Ec2NameResolver(nodeSettings));
InetAddress[] addresses = networkService.resolveBindHostAddresses(null);
assertThat(addresses, arrayContaining(networkService.resolveBindHostAddresses(new String[] { "_local_" })));
}

View File

@ -31,12 +31,14 @@ import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.discovery.DiscoveryModule;
import org.elasticsearch.discovery.gce.GceUnicastHostsProvider;
import org.elasticsearch.discovery.zen.ZenDiscovery;
import org.elasticsearch.plugins.DiscoveryPlugin;
import org.elasticsearch.plugins.Plugin;
import java.security.AccessController;
@ -47,7 +49,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class GceDiscoveryPlugin extends Plugin {
public class GceDiscoveryPlugin extends Plugin implements DiscoveryPlugin {
public static final String GCE = "gce";
private final Settings settings;
@ -100,9 +102,10 @@ public class GceDiscoveryPlugin extends Plugin {
discoveryModule.addUnicastHostProvider(GCE, GceUnicastHostsProvider.class);
}
public void onModule(NetworkModule networkModule) {
@Override
public NetworkService.CustomNameResolver getCustomNameResolver(Settings settings) {
logger.debug("Register _gce_, _gce:xxx network names");
networkModule.addCustomNameResolver(new GceNameResolver(settings, new GceMetadataServiceImpl(settings)));
return new GceNameResolver(settings, new GceMetadataServiceImpl(settings));
}
@Override

View File

@ -107,7 +107,7 @@ public class GceNetworkTests extends ESTestCase {
NetworkService networkService = new NetworkService(nodeSettings);
GceMetadataServiceMock mock = new GceMetadataServiceMock(nodeSettings);
networkService.setCustomNameResolvers(Collections.singletonList(new GceNameResolver(nodeSettings, mock)));
networkService.addCustomNameResolver(new GceNameResolver(nodeSettings, mock));
try {
InetAddress[] addresses = networkService.resolveBindHostAddresses(null);
if (expected == null) {