/* * 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 org.elasticsearch.Version; import org.elasticsearch.cloud.gce.GceInstancesServiceImpl; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.network.NetworkService; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Locale; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; /** * This test class uses a GCE HTTP Mock system which allows to simulate JSON Responses. * * To implement a new test you'll need to create an `instances.json` file which contains expected response * for a given project-id and zone under the src/test/resources/org/elasticsearch/discovery/gce with dir name: * * compute/v1/projects/[project-id]/zones/[zone] * * By default, project-id is the test method name, lowercase and missing the "test" prefix. * * For example, if you create a test `myNewAwesomeTest` with following settings: * * Settings nodeSettings = Settings.builder() * .put(GceComputeService.PROJECT, projectName) * .put(GceComputeService.ZONE, "europe-west1-b") * .build(); * * You need to create a file under `src/test/resources/org/elasticsearch/discovery/gce/` named: * * compute/v1/projects/mynewawesometest/zones/europe-west1-b/instances.json * */ public class GceDiscoveryTests extends ESTestCase { protected static ThreadPool threadPool; protected MockTransportService transportService; protected GceInstancesServiceMock mock; protected String projectName; @BeforeClass public static void createThreadPool() { threadPool = new TestThreadPool(GceDiscoveryTests.class.getName()); } @AfterClass public static void stopThreadPool() { if (threadPool != null) { threadPool.shutdownNow(); threadPool = null; } } @Before public void setProjectName() { projectName = getTestName().toLowerCase(Locale.ROOT); // Slice off the "test" part of the method names so the project names if (projectName.startsWith("test")) { projectName = projectName.substring("test".length()); } } @Before public void createTransportService() { transportService = MockTransportService.createNewService(Settings.EMPTY, Version.CURRENT, threadPool, null); } @After public void stopGceComputeService() throws IOException { if (mock != null) { mock.close(); } } protected List<DiscoveryNode> buildDynamicNodes(GceInstancesServiceImpl gceInstancesService, Settings nodeSettings) { GceUnicastHostsProvider provider = new GceUnicastHostsProvider(nodeSettings, gceInstancesService, transportService, new NetworkService(Settings.EMPTY, Collections.emptyList())); List<DiscoveryNode> discoveryNodes = provider.buildDynamicNodes(); logger.info("--> nodes found: {}", discoveryNodes); return discoveryNodes; } public void testNodesWithDifferentTagsAndNoTagSet() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .put(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "europe-west1-b") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(2)); } public void testNodesWithDifferentTagsAndOneTagSet() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .put(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "europe-west1-b") .putArray(GceUnicastHostsProvider.TAGS_SETTING.getKey(), "elasticsearch") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(1)); assertThat(discoveryNodes.get(0).getId(), is("#cloud-test2-0")); } public void testNodesWithDifferentTagsAndTwoTagSet() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .put(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "europe-west1-b") .putArray(GceUnicastHostsProvider.TAGS_SETTING.getKey(), "elasticsearch", "dev") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(1)); assertThat(discoveryNodes.get(0).getId(), is("#cloud-test2-0")); } public void testNodesWithSameTagsAndNoTagSet() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .put(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "europe-west1-b") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(2)); } public void testNodesWithSameTagsAndOneTagSet() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .put(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "europe-west1-b") .putArray(GceUnicastHostsProvider.TAGS_SETTING.getKey(), "elasticsearch") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(2)); } public void testNodesWithSameTagsAndTwoTagsSet() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .put(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "europe-west1-b") .putArray(GceUnicastHostsProvider.TAGS_SETTING.getKey(), "elasticsearch", "dev") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(2)); } public void testMultipleZonesAndTwoNodesInSameZone() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .putArray(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "us-central1-a", "europe-west1-b") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(2)); } public void testMultipleZonesAndTwoNodesInDifferentZones() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .putArray(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "us-central1-a", "europe-west1-b") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(2)); } /** * For issue https://github.com/elastic/elasticsearch-cloud-gce/issues/43 */ public void testZeroNode43() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .putArray(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "us-central1-a", "us-central1-b") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(0)); } public void testIllegalSettingsMissingAllRequired() { Settings nodeSettings = Settings.EMPTY; mock = new GceInstancesServiceMock(nodeSettings); try { buildDynamicNodes(mock, nodeSettings); fail("We expect an IllegalArgumentException for incomplete settings"); } catch (IllegalArgumentException expected) { assertThat(expected.getMessage(), containsString("one or more gce discovery settings are missing.")); } } public void testIllegalSettingsMissingProject() { Settings nodeSettings = Settings.builder() .putArray(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "us-central1-a", "us-central1-b") .build(); mock = new GceInstancesServiceMock(nodeSettings); try { buildDynamicNodes(mock, nodeSettings); fail("We expect an IllegalArgumentException for incomplete settings"); } catch (IllegalArgumentException expected) { assertThat(expected.getMessage(), containsString("one or more gce discovery settings are missing.")); } } public void testIllegalSettingsMissingZone() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .build(); mock = new GceInstancesServiceMock(nodeSettings); try { buildDynamicNodes(mock, nodeSettings); fail("We expect an IllegalArgumentException for incomplete settings"); } catch (IllegalArgumentException expected) { assertThat(expected.getMessage(), containsString("one or more gce discovery settings are missing.")); } } /** * For issue https://github.com/elastic/elasticsearch/issues/16967: * When using multiple regions and one of them has no instance at all, this * was producing a NPE as a result. */ public void testNoRegionReturnsEmptyList() { Settings nodeSettings = Settings.builder() .put(GceInstancesServiceImpl.PROJECT_SETTING.getKey(), projectName) .putArray(GceInstancesServiceImpl.ZONE_SETTING.getKey(), "europe-west1-b", "us-central1-a") .build(); mock = new GceInstancesServiceMock(nodeSettings); List<DiscoveryNode> discoveryNodes = buildDynamicNodes(mock, nodeSettings); assertThat(discoveryNodes, hasSize(1)); } }