Allow `_gce_` network when not using discovery gce
For now we support `_gce_` only if discovery is set to `gce` and all information about GCE is provided (project_id and zone). But in some cases, people would like to only bind to `_gce_` on a single node (without any elasticsearch cluster). They could access the machine then from other machines running inside the same project. This commit adds a new GceMetadataService which is started as soon as the plugin is started so GceNameResolver can use it to resolve `_gce`. Closes #15724.
This commit is contained in:
parent
2232a7cdf3
commit
c16d309c8c
|
@ -76,19 +76,4 @@ public interface GceComputeService extends LifecycleComponent<GceComputeService>
|
|||
* @return a collection of running instances within the same GCE project
|
||||
*/
|
||||
Collection<Instance> instances();
|
||||
|
||||
/**
|
||||
* <p>Gets metadata on the current running machine (call to
|
||||
* http://metadata.google.internal/computeMetadata/v1/instance/xxx).</p>
|
||||
* <p>For example, you can retrieve network information by replacing xxx with:</p>
|
||||
* <ul>
|
||||
* <li>`hostname` when we need to resolve the host name</li>
|
||||
* <li>`network-interfaces/0/ip` when we need to resolve private IP</li>
|
||||
* </ul>
|
||||
* @see org.elasticsearch.cloud.gce.network.GceNameResolver for bindings
|
||||
* @param metadataPath path to metadata information
|
||||
* @return extracted information (for example a hostname or an IP address)
|
||||
* @throws IOException in case metadata URL is not accessible
|
||||
*/
|
||||
String metadata(String metadataPath) throws IOException;
|
||||
}
|
||||
|
|
|
@ -116,47 +116,6 @@ public class GceComputeServiceImpl extends AbstractLifecycleComponent<GceCompute
|
|||
return instances;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metadata(String metadataPath) throws IOException {
|
||||
String urlMetadataNetwork = this.metaDataUrl + "/" + metadataPath;
|
||||
logger.debug("get metadata from [{}]", urlMetadataNetwork);
|
||||
final URL url = new URL(urlMetadataNetwork);
|
||||
HttpHeaders headers;
|
||||
try {
|
||||
// hack around code messiness in GCE code
|
||||
// TODO: get this fixed
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new SpecialPermission());
|
||||
}
|
||||
headers = AccessController.doPrivileged(new PrivilegedExceptionAction<HttpHeaders>() {
|
||||
@Override
|
||||
public HttpHeaders run() throws IOException {
|
||||
return new HttpHeaders();
|
||||
}
|
||||
});
|
||||
GenericUrl genericUrl = AccessController.doPrivileged(new PrivilegedAction<GenericUrl>() {
|
||||
@Override
|
||||
public GenericUrl run() {
|
||||
return new GenericUrl(url);
|
||||
}
|
||||
});
|
||||
|
||||
// This is needed to query meta data: https://cloud.google.com/compute/docs/metadata
|
||||
headers.put("Metadata-Flavor", "Google");
|
||||
HttpResponse response;
|
||||
response = getGceHttpTransport().createRequestFactory()
|
||||
.buildGetRequest(genericUrl)
|
||||
.setHeaders(headers)
|
||||
.execute();
|
||||
String metadata = response.parseAsString();
|
||||
logger.debug("metadata found [{}]", metadata);
|
||||
return metadata;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("failed to fetch metadata from [" + urlMetadataNetwork + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Compute client;
|
||||
private TimeValue refreshInterval = null;
|
||||
private long lastRefresh;
|
||||
|
@ -168,17 +127,17 @@ public class GceComputeServiceImpl extends AbstractLifecycleComponent<GceCompute
|
|||
private JsonFactory gceJsonFactory;
|
||||
|
||||
private final boolean validateCerts;
|
||||
|
||||
@Inject
|
||||
public GceComputeServiceImpl(Settings settings, NetworkService networkService) {
|
||||
public GceComputeServiceImpl(Settings settings) {
|
||||
super(settings);
|
||||
this.project = PROJECT_SETTING.get(settings);
|
||||
this.zones = ZONE_SETTING.get(settings);
|
||||
this.gceHost = GCE_HOST.get(settings);
|
||||
this.metaDataUrl = gceHost + "/computeMetadata/v1/instance";
|
||||
this.gceRootUrl = GCE_ROOT_URL.get(settings);
|
||||
tokenServerEncodedUrl = metaDataUrl + "/service-accounts/default/token";
|
||||
this.tokenServerEncodedUrl = metaDataUrl + "/service-accounts/default/token";
|
||||
this.validateCerts = GCE_VALIDATE_CERTIFICATES.get(settings);
|
||||
networkService.addCustomNameResolver(new GceNameResolver(settings, this));
|
||||
}
|
||||
|
||||
protected synchronized HttpTransport getGceHttpTransport() throws GeneralSecurityException, IOException {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.cloud.gce;
|
||||
|
||||
import org.elasticsearch.common.component.LifecycleComponent;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Access Google Compute Engine metadata
|
||||
*/
|
||||
public interface GceMetadataService extends LifecycleComponent<GceMetadataService> {
|
||||
/**
|
||||
* <p>Gets metadata on the current running machine (call to
|
||||
* http://metadata.google.internal/computeMetadata/v1/instance/xxx).</p>
|
||||
* <p>For example, you can retrieve network information by replacing xxx with:</p>
|
||||
* <ul>
|
||||
* <li>`hostname` when we need to resolve the host name</li>
|
||||
* <li>`network-interfaces/0/ip` when we need to resolve private IP</li>
|
||||
* </ul>
|
||||
* @see org.elasticsearch.cloud.gce.network.GceNameResolver for bindings
|
||||
* @param metadataPath path to metadata information
|
||||
* @return extracted information (for example a hostname or an IP address)
|
||||
* @throws IOException in case metadata URL is not accessible
|
||||
*/
|
||||
String metadata(String metadataPath) throws IOException;
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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.cloud.gce;
|
||||
|
||||
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpHeaders;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import org.elasticsearch.SpecialPermission;
|
||||
import org.elasticsearch.cloud.gce.network.GceNameResolver;
|
||||
import org.elasticsearch.common.component.AbstractLifecycleComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class GceMetadataServiceImpl extends AbstractLifecycleComponent<GceMetadataService> implements GceMetadataService {
|
||||
|
||||
// Forcing Google Token API URL as set in GCE SDK to
|
||||
// http://metadata/computeMetadata/v1/instance/service-accounts/default/token
|
||||
// See https://developers.google.com/compute/docs/metadata#metadataserver
|
||||
// all settings just used for testing - not registered by default
|
||||
public static final Setting<String> GCE_HOST =
|
||||
new Setting<>("cloud.gce.host", "http://metadata.google.internal", Function.identity(), Setting.Property.NodeScope);
|
||||
|
||||
/** Global instance of the HTTP transport. */
|
||||
private HttpTransport gceHttpTransport;
|
||||
|
||||
// Forcing Google Token API URL as set in GCE SDK to
|
||||
// http://metadata/computeMetadata/v1/instance/service-accounts/default/token
|
||||
// See https://developers.google.com/compute/docs/metadata#metadataserver
|
||||
private final String gceHost;
|
||||
private final String metaDataUrl;
|
||||
|
||||
@Inject
|
||||
public GceMetadataServiceImpl(Settings settings, NetworkService networkService) {
|
||||
super(settings);
|
||||
networkService.addCustomNameResolver(new GceNameResolver(settings, this));
|
||||
this.gceHost = GCE_HOST.get(settings);
|
||||
this.metaDataUrl = gceHost + "/computeMetadata/v1/instance";
|
||||
}
|
||||
|
||||
protected synchronized HttpTransport getGceHttpTransport() throws GeneralSecurityException, IOException {
|
||||
if (gceHttpTransport == null) {
|
||||
gceHttpTransport = GoogleNetHttpTransport.newTrustedTransport();
|
||||
}
|
||||
return gceHttpTransport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metadata(String metadataPath) throws IOException {
|
||||
String urlMetadataNetwork = this.metaDataUrl + "/" + metadataPath;
|
||||
logger.debug("get metadata from [{}]", urlMetadataNetwork);
|
||||
final URL url = new URL(urlMetadataNetwork);
|
||||
HttpHeaders headers;
|
||||
try {
|
||||
// hack around code messiness in GCE code
|
||||
// TODO: get this fixed
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new SpecialPermission());
|
||||
}
|
||||
headers = AccessController.doPrivileged(new PrivilegedExceptionAction<HttpHeaders>() {
|
||||
@Override
|
||||
public HttpHeaders run() throws IOException {
|
||||
return new HttpHeaders();
|
||||
}
|
||||
});
|
||||
GenericUrl genericUrl = AccessController.doPrivileged(new PrivilegedAction<GenericUrl>() {
|
||||
@Override
|
||||
public GenericUrl run() {
|
||||
return new GenericUrl(url);
|
||||
}
|
||||
});
|
||||
|
||||
// This is needed to query meta data: https://cloud.google.com/compute/docs/metadata
|
||||
headers.put("Metadata-Flavor", "Google");
|
||||
HttpResponse response;
|
||||
response = getGceHttpTransport().createRequestFactory()
|
||||
.buildGetRequest(genericUrl)
|
||||
.setHeaders(headers)
|
||||
.execute();
|
||||
String metadata = response.parseAsString();
|
||||
logger.debug("metadata found [{}]", metadata);
|
||||
return metadata;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("failed to fetch metadata from [" + urlMetadataNetwork + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
if (gceHttpTransport != null) {
|
||||
try {
|
||||
gceHttpTransport.shutdown();
|
||||
} catch (IOException e) {
|
||||
logger.warn("unable to shutdown GCE Http Transport", e);
|
||||
}
|
||||
gceHttpTransport = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose() {
|
||||
|
||||
}
|
||||
}
|
|
@ -20,17 +20,34 @@
|
|||
package org.elasticsearch.cloud.gce;
|
||||
|
||||
import org.elasticsearch.common.inject.AbstractModule;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
public class GceModule extends AbstractModule {
|
||||
// pkg private so tests can override with mock
|
||||
static Class<? extends GceComputeService> computeServiceImpl = GceComputeServiceImpl.class;
|
||||
static Class<? extends GceMetadataService> metadataServiceImpl = GceMetadataServiceImpl.class;
|
||||
|
||||
protected final Settings settings;
|
||||
protected final ESLogger logger = Loggers.getLogger(GceModule.class);
|
||||
|
||||
public GceModule(Settings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public static Class<? extends GceComputeService> getComputeServiceImpl() {
|
||||
return computeServiceImpl;
|
||||
}
|
||||
|
||||
public static Class<? extends GceMetadataService> getMetadataServiceImpl() {
|
||||
return metadataServiceImpl;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
logger.debug("configure GceModule (bind compute and metadata services)");
|
||||
bind(GceComputeService.class).to(computeServiceImpl).asEagerSingleton();
|
||||
bind(GceMetadataService.class).to(metadataServiceImpl).asEagerSingleton();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.elasticsearch.cloud.gce.network;
|
||||
|
||||
import org.elasticsearch.cloud.gce.GceComputeService;
|
||||
import org.elasticsearch.cloud.gce.GceMetadataService;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.network.NetworkService.CustomNameResolver;
|
||||
|
@ -40,7 +41,7 @@ import java.net.InetAddress;
|
|||
*/
|
||||
public class GceNameResolver extends AbstractComponent implements CustomNameResolver {
|
||||
|
||||
private final GceComputeService gceComputeService;
|
||||
private final GceMetadataService gceMetadataService;
|
||||
|
||||
/**
|
||||
* enum that can be added to over time with more meta-data types
|
||||
|
@ -72,9 +73,9 @@ public class GceNameResolver extends AbstractComponent implements CustomNameReso
|
|||
/**
|
||||
* Construct a {@link CustomNameResolver}.
|
||||
*/
|
||||
public GceNameResolver(Settings settings, GceComputeService gceComputeService) {
|
||||
public GceNameResolver(Settings settings, GceMetadataService gceMetadataService) {
|
||||
super(settings);
|
||||
this.gceComputeService = gceComputeService;
|
||||
this.gceMetadataService = gceMetadataService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,7 +106,7 @@ public class GceNameResolver extends AbstractComponent implements CustomNameReso
|
|||
}
|
||||
|
||||
try {
|
||||
String metadataResult = gceComputeService.metadata(gceMetadataPath);
|
||||
String metadataResult = gceMetadataService.metadata(gceMetadataPath);
|
||||
if (metadataResult == null || metadataResult.length() == 0) {
|
||||
throw new IOException("no gce metadata returned from [" + gceMetadataPath + "] for [" + value + "]");
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.elasticsearch.plugins.Plugin;
|
|||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
|
@ -85,22 +86,27 @@ public class GceDiscoveryPlugin extends Plugin {
|
|||
|
||||
@Override
|
||||
public Collection<Module> nodeModules() {
|
||||
return Collections.singletonList(new GceModule());
|
||||
return Collections.singletonList(new GceModule(settings));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes") // Supertype uses raw type
|
||||
public Collection<Class<? extends LifecycleComponent>> nodeServices() {
|
||||
return Collections.singletonList(GceModule.getComputeServiceImpl());
|
||||
logger.debug("Register gce compute and metadata services");
|
||||
Collection<Class<? extends LifecycleComponent>> services = new ArrayList<>();
|
||||
services.add(GceModule.getComputeServiceImpl());
|
||||
services.add(GceModule.getMetadataServiceImpl());
|
||||
return services;
|
||||
}
|
||||
|
||||
public void onModule(DiscoveryModule discoveryModule) {
|
||||
logger.debug("Register gce discovery type and gce unicast provider");
|
||||
discoveryModule.addDiscoveryType(GCE, ZenDiscovery.class);
|
||||
// If discovery.type: gce, we add Gce as a unicast provider
|
||||
discoveryModule.addUnicastHostProvider(GCE, GceUnicastHostsProvider.class);
|
||||
discoveryModule.addUnicastHostProvider(GCE, GceUnicastHostsProvider.class);
|
||||
}
|
||||
|
||||
public void onModule(SettingsModule settingsModule) {
|
||||
logger.debug("registering GCE Settings");
|
||||
// Register GCE settings
|
||||
settingsModule.registerSetting(GceComputeService.PROJECT_SETTING);
|
||||
settingsModule.registerSetting(GceComputeService.ZONE_SETTING);
|
||||
|
|
|
@ -45,69 +45,13 @@ public class GceComputeServiceMock extends GceComputeServiceImpl {
|
|||
|
||||
protected HttpTransport mockHttpTransport;
|
||||
|
||||
public GceComputeServiceMock(Settings settings, NetworkService networkService) {
|
||||
super(settings, networkService);
|
||||
this.mockHttpTransport = configureMock();
|
||||
public GceComputeServiceMock(Settings settings) {
|
||||
super(settings);
|
||||
this.mockHttpTransport = GceMockUtils.configureMock();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpTransport getGceHttpTransport() throws GeneralSecurityException, IOException {
|
||||
return this.mockHttpTransport;
|
||||
}
|
||||
|
||||
public static final String GCE_METADATA_URL = "http://metadata.google.internal/computeMetadata/v1/instance";
|
||||
|
||||
protected HttpTransport configureMock() {
|
||||
return new MockHttpTransport() {
|
||||
@Override
|
||||
public LowLevelHttpRequest buildRequest(String method, final String url) throws IOException {
|
||||
return new MockLowLevelHttpRequest() {
|
||||
@Override
|
||||
public LowLevelHttpResponse execute() throws IOException {
|
||||
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
|
||||
response.setStatusCode(200);
|
||||
response.setContentType(Json.MEDIA_TYPE);
|
||||
if (url.startsWith(GCE_METADATA_URL)) {
|
||||
logger.info("--> Simulate GCE Auth/Metadata response for [{}]", url);
|
||||
response.setContent(readGoogleInternalJsonResponse(url));
|
||||
} else {
|
||||
logger.info("--> Simulate GCE API response for [{}]", url);
|
||||
response.setContent(readGoogleApiJsonResponse(url));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static String readGoogleInternalJsonResponse(String url) throws IOException {
|
||||
return readJsonResponse(url, "http://metadata.google.internal/");
|
||||
}
|
||||
|
||||
public static String readGoogleApiJsonResponse(String url) throws IOException {
|
||||
return readJsonResponse(url, "https://www.googleapis.com/");
|
||||
}
|
||||
|
||||
private static String readJsonResponse(String url, String urlRoot) throws IOException {
|
||||
// We extract from the url the mock file path we want to use
|
||||
String mockFileName = Strings.replace(url, urlRoot, "");
|
||||
|
||||
URL resource = GceComputeServiceMock.class.getResource(mockFileName);
|
||||
if (resource == null) {
|
||||
throw new IOException("can't read [" + url + "] in src/test/resources/org/elasticsearch/discovery/gce");
|
||||
}
|
||||
try (InputStream is = resource.openStream()) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
Streams.readAllLines(is, new Callback<String>() {
|
||||
@Override
|
||||
public void handle(String s) {
|
||||
sb.append(s);
|
||||
}
|
||||
});
|
||||
String response = sb.toString();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ public class GceDiscoverTests extends ESIntegTestCase {
|
|||
httpServer = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress().getHostAddress(), 0), 0);
|
||||
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
|
||||
httpServer.createContext("/computeMetadata/v1/instance/service-accounts/default/token", (s) -> {
|
||||
String response = GceComputeServiceMock.readGoogleInternalJsonResponse(
|
||||
String response = GceMockUtils.readGoogleInternalJsonResponse(
|
||||
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token");
|
||||
byte[] responseAsBytes = response.getBytes(StandardCharsets.UTF_8);
|
||||
s.sendResponseHeaders(200, responseAsBytes.length);
|
||||
|
|
|
@ -65,7 +65,6 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
|
||||
protected static ThreadPool threadPool;
|
||||
protected MockTransportService transportService;
|
||||
protected NetworkService networkService;
|
||||
protected GceComputeService mock;
|
||||
protected String projectName;
|
||||
|
||||
|
@ -96,11 +95,6 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
transportService = MockTransportService.local(Settings.EMPTY, Version.CURRENT, threadPool);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createNetworkService() {
|
||||
networkService = new NetworkService(Settings.EMPTY);
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopGceComputeService() {
|
||||
if (mock != null) {
|
||||
|
@ -122,7 +116,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.PROJECT_SETTING.getKey(), projectName)
|
||||
.put(GceComputeService.ZONE_SETTING.getKey(), "europe-west1-b")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(2));
|
||||
}
|
||||
|
@ -133,7 +127,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.ZONE_SETTING.getKey(), "europe-west1-b")
|
||||
.putArray(GceUnicastHostsProvider.TAGS_SETTING.getKey(), "elasticsearch")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(1));
|
||||
assertThat(discoveryNodes.get(0).getId(), is("#cloud-test2-0"));
|
||||
|
@ -145,7 +139,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.ZONE_SETTING.getKey(), "europe-west1-b")
|
||||
.putArray(GceUnicastHostsProvider.TAGS_SETTING.getKey(), "elasticsearch", "dev")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(1));
|
||||
assertThat(discoveryNodes.get(0).getId(), is("#cloud-test2-0"));
|
||||
|
@ -156,7 +150,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.PROJECT_SETTING.getKey(), projectName)
|
||||
.put(GceComputeService.ZONE_SETTING.getKey(), "europe-west1-b")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(2));
|
||||
}
|
||||
|
@ -167,7 +161,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.ZONE_SETTING.getKey(), "europe-west1-b")
|
||||
.putArray(GceUnicastHostsProvider.TAGS_SETTING.getKey(), "elasticsearch")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(2));
|
||||
}
|
||||
|
@ -178,7 +172,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.ZONE_SETTING.getKey(), "europe-west1-b")
|
||||
.putArray(GceUnicastHostsProvider.TAGS_SETTING.getKey(), "elasticsearch", "dev")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(2));
|
||||
}
|
||||
|
@ -188,7 +182,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.PROJECT_SETTING.getKey(), projectName)
|
||||
.putArray(GceComputeService.ZONE_SETTING.getKey(), "us-central1-a", "europe-west1-b")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(2));
|
||||
}
|
||||
|
@ -198,7 +192,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.PROJECT_SETTING.getKey(), projectName)
|
||||
.putArray(GceComputeService.ZONE_SETTING.getKey(), "us-central1-a", "europe-west1-b")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(2));
|
||||
}
|
||||
|
@ -211,14 +205,14 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
.put(GceComputeService.PROJECT_SETTING.getKey(), projectName)
|
||||
.putArray(GceComputeService.ZONE_SETTING.getKey(), "us-central1-a", "us-central1-b")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings);
|
||||
assertThat(discoveryNodes, hasSize(0));
|
||||
}
|
||||
|
||||
public void testIllegalSettingsMissingAllRequired() {
|
||||
Settings nodeSettings = Settings.EMPTY;
|
||||
mock = new GceComputeServiceMock(Settings.EMPTY, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
try {
|
||||
buildDynamicNodes(mock, nodeSettings);
|
||||
fail("We expect an IllegalArgumentException for incomplete settings");
|
||||
|
@ -231,7 +225,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
Settings nodeSettings = Settings.builder()
|
||||
.putArray(GceComputeService.ZONE_SETTING.getKey(), "us-central1-a", "us-central1-b")
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
try {
|
||||
buildDynamicNodes(mock, nodeSettings);
|
||||
fail("We expect an IllegalArgumentException for incomplete settings");
|
||||
|
@ -244,7 +238,7 @@ public class GceDiscoveryTests extends ESTestCase {
|
|||
Settings nodeSettings = Settings.builder()
|
||||
.put(GceComputeService.PROJECT_SETTING.getKey(), projectName)
|
||||
.build();
|
||||
mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
mock = new GceComputeServiceMock(nodeSettings);
|
||||
try {
|
||||
buildDynamicNodes(mock, nodeSettings);
|
||||
fail("We expect an IllegalArgumentException for incomplete settings");
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.discovery.gce;
|
||||
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import org.elasticsearch.cloud.gce.GceComputeServiceImpl;
|
||||
import org.elasticsearch.cloud.gce.GceMetadataServiceImpl;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Mock for GCE Metadata Service
|
||||
*/
|
||||
public class GceMetadataServiceMock extends GceMetadataServiceImpl {
|
||||
|
||||
protected HttpTransport mockHttpTransport;
|
||||
|
||||
public GceMetadataServiceMock(Settings settings, NetworkService networkService) {
|
||||
super(settings, networkService);
|
||||
this.mockHttpTransport = GceMockUtils.configureMock();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpTransport getGceHttpTransport() throws GeneralSecurityException, IOException {
|
||||
return this.mockHttpTransport;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.discovery.gce;
|
||||
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.LowLevelHttpRequest;
|
||||
import com.google.api.client.http.LowLevelHttpResponse;
|
||||
import com.google.api.client.json.Json;
|
||||
import com.google.api.client.testing.http.MockHttpTransport;
|
||||
import com.google.api.client.testing.http.MockLowLevelHttpRequest;
|
||||
import com.google.api.client.testing.http.MockLowLevelHttpResponse;
|
||||
import org.elasticsearch.cloud.gce.GceMetadataServiceImpl;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.util.Callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
public class GceMockUtils {
|
||||
protected final static ESLogger logger = Loggers.getLogger(GceMockUtils.class);
|
||||
|
||||
public static final String GCE_METADATA_URL = "http://metadata.google.internal/computeMetadata/v1/instance";
|
||||
|
||||
protected static HttpTransport configureMock() {
|
||||
return new MockHttpTransport() {
|
||||
@Override
|
||||
public LowLevelHttpRequest buildRequest(String method, final String url) throws IOException {
|
||||
return new MockLowLevelHttpRequest() {
|
||||
@Override
|
||||
public LowLevelHttpResponse execute() throws IOException {
|
||||
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
|
||||
response.setStatusCode(200);
|
||||
response.setContentType(Json.MEDIA_TYPE);
|
||||
if (url.startsWith(GCE_METADATA_URL)) {
|
||||
logger.info("--> Simulate GCE Auth/Metadata response for [{}]", url);
|
||||
response.setContent(readGoogleInternalJsonResponse(url));
|
||||
} else {
|
||||
logger.info("--> Simulate GCE API response for [{}]", url);
|
||||
response.setContent(readGoogleApiJsonResponse(url));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static String readGoogleInternalJsonResponse(String url) throws IOException {
|
||||
return readJsonResponse(url, "http://metadata.google.internal/");
|
||||
}
|
||||
|
||||
public static String readGoogleApiJsonResponse(String url) throws IOException {
|
||||
return readJsonResponse(url, "https://www.googleapis.com/");
|
||||
}
|
||||
|
||||
private static String readJsonResponse(String url, String urlRoot) throws IOException {
|
||||
// We extract from the url the mock file path we want to use
|
||||
String mockFileName = Strings.replace(url, urlRoot, "");
|
||||
|
||||
URL resource = GceComputeServiceMock.class.getResource(mockFileName);
|
||||
if (resource == null) {
|
||||
throw new IOException("can't read [" + url + "] in src/test/resources/org/elasticsearch/discovery/gce");
|
||||
}
|
||||
try (InputStream is = resource.openStream()) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
Streams.readAllLines(is, new Callback<String>() {
|
||||
@Override
|
||||
public void handle(String s) {
|
||||
sb.append(s);
|
||||
}
|
||||
});
|
||||
String response = sb.toString();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -104,7 +104,7 @@ public class GceNetworkTests extends ESTestCase {
|
|||
.build();
|
||||
|
||||
NetworkService networkService = new NetworkService(nodeSettings);
|
||||
GceComputeServiceMock mock = new GceComputeServiceMock(nodeSettings, networkService);
|
||||
GceMetadataServiceMock mock = new GceMetadataServiceMock(nodeSettings, networkService);
|
||||
networkService.addCustomNameResolver(new GceNameResolver(nodeSettings, mock));
|
||||
try {
|
||||
InetAddress[] addresses = networkService.resolveBindHostAddresses(null);
|
||||
|
|
Loading…
Reference in New Issue