Skip to content

Commit 59b34ba

Browse files
committed
Merge branch 'pr/22566-ec2-meta-host'
2 parents a475323 + 6e7aee0 commit 59b34ba

File tree

4 files changed

+94
-33
lines changed

4 files changed

+94
-33
lines changed

docs/plugins/discovery-ec2.asciidoc

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,20 @@ The following are a list of settings (prefixed with `discovery.ec2`) that can fu
172172

173173
`host_type`::
174174

175-
The type of host type to use to communicate with other instances. Can be
176-
one of `private_ip`, `public_ip`, `private_dns`, `public_dns`. Defaults to
177-
`private_ip`.
175+
+
176+
--
177+
The type of host type to use to communicate with other instances. Can be
178+
one of `private_ip`, `public_ip`, `private_dns`, `public_dns` or `tag:TAGNAME` where
179+
`TAGNAME` refers to a name of a tag configured for all EC2 instances. Instances which don't
180+
have this tag set will be ignored by the discovery process.
181+
182+
For example if you defined a tag `my-elasticsearch-host` in ec2 and set it to `myhostname1.mydomain.com`, then
183+
setting `host_type: tag:my-elasticsearch-host` will tell Discovery Ec2 plugin to read the host name from the
184+
`my-elasticsearch-host` tag. In this case, it will be resolved to `myhostname1.mydomain.com`.
185+
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html[Read more about EC2 Tags].
186+
187+
Defaults to `private_ip`.
188+
--
178189

179190
`availability_zones`::
180191

plugins/discovery-ec2/src/main/java/org/elasticsearch/cloud/aws/AwsEc2Service.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,20 +164,22 @@ interface CLOUD_EC2 {
164164
* Defines discovery settings for ec2. Starting with discovery.ec2.
165165
*/
166166
interface DISCOVERY_EC2 {
167-
enum HostType {
168-
PRIVATE_IP,
169-
PUBLIC_IP,
170-
PRIVATE_DNS,
171-
PUBLIC_DNS
167+
class HostType {
168+
public static final String PRIVATE_IP = "private_ip";
169+
public static final String PUBLIC_IP = "public_ip";
170+
public static final String PRIVATE_DNS = "private_dns";
171+
public static final String PUBLIC_DNS = "public_dns";
172+
public static final String TAG_PREFIX = "tag:";
172173
}
173174

174175
/**
175176
* discovery.ec2.host_type: The type of host type to use to communicate with other instances.
176-
* Can be one of private_ip, public_ip, private_dns, public_dns. Defaults to private_ip.
177+
* Can be one of private_ip, public_ip, private_dns, public_dns or tag:XXXX where
178+
* XXXX refers to a name of a tag configured for all EC2 instances. Instances which don't
179+
* have this tag set will be ignored by the discovery process. Defaults to private_ip.
177180
*/
178-
Setting<HostType> HOST_TYPE_SETTING =
179-
new Setting<>("discovery.ec2.host_type", HostType.PRIVATE_IP.name(), s -> HostType.valueOf(s.toUpperCase(Locale.ROOT)),
180-
Property.NodeScope);
181+
Setting<String> HOST_TYPE_SETTING =
182+
new Setting<>("discovery.ec2.host_type", HostType.PRIVATE_IP, Function.identity(), Property.NodeScope);
181183
/**
182184
* discovery.ec2.any_group: If set to false, will require all security groups to be present for the instance to be used for the
183185
* discovery. Defaults to true.

plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2UnicastHostsProvider.java

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.amazonaws.services.ec2.model.GroupIdentifier;
2828
import com.amazonaws.services.ec2.model.Instance;
2929
import com.amazonaws.services.ec2.model.Reservation;
30+
import com.amazonaws.services.ec2.model.Tag;
3031
import org.apache.logging.log4j.message.ParameterizedMessage;
3132
import org.apache.logging.log4j.util.Supplier;
3233
import org.elasticsearch.Version;
@@ -51,6 +52,11 @@
5152
import static java.util.Collections.disjoint;
5253
import static java.util.Collections.emptyMap;
5354
import static java.util.Collections.emptySet;
55+
import static org.elasticsearch.cloud.aws.AwsEc2Service.DISCOVERY_EC2.HostType.TAG_PREFIX;
56+
import static org.elasticsearch.cloud.aws.AwsEc2Service.DISCOVERY_EC2.HostType.PRIVATE_DNS;
57+
import static org.elasticsearch.cloud.aws.AwsEc2Service.DISCOVERY_EC2.HostType.PRIVATE_IP;
58+
import static org.elasticsearch.cloud.aws.AwsEc2Service.DISCOVERY_EC2.HostType.PUBLIC_DNS;
59+
import static org.elasticsearch.cloud.aws.AwsEc2Service.DISCOVERY_EC2.HostType.PUBLIC_IP;
5460

5561
public class AwsEc2UnicastHostsProvider extends AbstractComponent implements UnicastHostsProvider {
5662

@@ -66,7 +72,7 @@ public class AwsEc2UnicastHostsProvider extends AbstractComponent implements Uni
6672

6773
private final Set<String> availabilityZones;
6874

69-
private final DISCOVERY_EC2.HostType hostType;
75+
private final String hostType;
7076

7177
private final DiscoNodesCache discoNodes;
7278

@@ -149,28 +155,36 @@ && disjoint(securityGroupIds, groups)) {
149155
}
150156

151157
String address = null;
152-
switch (hostType) {
153-
case PRIVATE_DNS:
154-
address = instance.getPrivateDnsName();
155-
break;
156-
case PRIVATE_IP:
157-
address = instance.getPrivateIpAddress();
158-
break;
159-
case PUBLIC_DNS:
160-
address = instance.getPublicDnsName();
161-
break;
162-
case PUBLIC_IP:
163-
address = instance.getPublicIpAddress();
164-
break;
158+
if (hostType.equals(PRIVATE_DNS)) {
159+
address = instance.getPrivateDnsName();
160+
} else if (hostType.equals(PRIVATE_IP)) {
161+
address = instance.getPrivateIpAddress();
162+
} else if (hostType.equals(PUBLIC_DNS)) {
163+
address = instance.getPublicDnsName();
164+
} else if (hostType.equals(PUBLIC_IP)) {
165+
address = instance.getPublicIpAddress();
166+
} else if (hostType.startsWith(TAG_PREFIX)) {
167+
// Reading the node host from its metadata
168+
String tagName = hostType.substring(TAG_PREFIX.length());
169+
logger.debug("reading hostname from [{}] instance tag", tagName);
170+
List<Tag> tags = instance.getTags();
171+
for (Tag tag : tags) {
172+
if (tag.getKey().equals(tagName)) {
173+
address = tag.getValue();
174+
logger.debug("using [{}] as the instance address", address);
175+
}
176+
}
177+
} else {
178+
throw new IllegalArgumentException(hostType + " is unknown for discovery.ec2.host_type");
165179
}
166180
if (address != null) {
167181
try {
168182
// we only limit to 1 port per address, makes no sense to ping 100 ports
169183
TransportAddress[] addresses = transportService.addressesFromString(address, 1);
170184
for (int i = 0; i < addresses.length; i++) {
171185
logger.trace("adding {}, address {}, transport_address {}", instance.getInstanceId(), address, addresses[i]);
172-
discoNodes.add(new DiscoveryNode("#cloud-" + instance.getInstanceId() + "-" + i, addresses[i],
173-
emptyMap(), emptySet(), Version.CURRENT.minimumCompatibilityVersion()));
186+
discoNodes.add(new DiscoveryNode(instance.getInstanceId(), "#cloud-" + instance.getInstanceId() + "-" + i,
187+
addresses[i], emptyMap(), emptySet(), Version.CURRENT.minimumCompatibilityVersion()));
174188
}
175189
} catch (Exception e) {
176190
final String finalAddress = address;

plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryTests.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.junit.Before;
4242
import org.junit.BeforeClass;
4343

44+
import java.net.InetAddress;
4445
import java.net.UnknownHostException;
4546
import java.util.ArrayList;
4647
import java.util.Collections;
@@ -51,6 +52,7 @@
5152
import static org.hamcrest.Matchers.containsString;
5253
import static org.hamcrest.Matchers.hasSize;
5354
import static org.hamcrest.Matchers.is;
55+
import static org.hamcrest.Matchers.isOneOf;
5456

5557
public class Ec2DiscoveryTests extends ESTestCase {
5658

@@ -195,12 +197,11 @@ public void testInvalidHostType() throws InterruptedException {
195197
Settings nodeSettings = Settings.builder()
196198
.put(DISCOVERY_EC2.HOST_TYPE_SETTING.getKey(), "does_not_exist")
197199
.build();
198-
try {
200+
201+
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> {
199202
buildDynamicNodes(nodeSettings, 1);
200-
fail("Expected IllegalArgumentException");
201-
} catch (IllegalArgumentException e) {
202-
assertThat(e.getMessage(), containsString("No enum constant"));
203-
}
203+
});
204+
assertThat(exception.getMessage(), containsString("does_not_exist is unknown for discovery.ec2.host_type"));
204205
}
205206

206207
public void testFilterByTags() throws InterruptedException {
@@ -259,6 +260,39 @@ public void testFilterByMultipleTags() throws InterruptedException {
259260
assertThat(discoveryNodes, hasSize(prodInstances));
260261
}
261262

263+
public void testReadHostFromTag() throws InterruptedException, UnknownHostException {
264+
int nodes = randomIntBetween(5, 10);
265+
266+
String[] addresses = new String[nodes];
267+
268+
for (int node = 0; node < nodes; node++) {
269+
addresses[node] = "192.168.0." + (node + 1);
270+
poorMansDNS.put("node" + (node + 1), new TransportAddress(InetAddress.getByName(addresses[node]), 9300));
271+
}
272+
273+
Settings nodeSettings = Settings.builder()
274+
.put(DISCOVERY_EC2.HOST_TYPE_SETTING.getKey(), "tag:foo")
275+
.build();
276+
277+
List<List<Tag>> tagsList = new ArrayList<>();
278+
279+
for (int node = 0; node < nodes; node++) {
280+
List<Tag> tags = new ArrayList<>();
281+
tags.add(new Tag("foo", "node" + (node + 1)));
282+
tagsList.add(tags);
283+
}
284+
285+
logger.info("started [{}] instances", nodes);
286+
List<DiscoveryNode> discoveryNodes = buildDynamicNodes(nodeSettings, nodes, tagsList);
287+
assertThat(discoveryNodes, hasSize(nodes));
288+
for (DiscoveryNode discoveryNode : discoveryNodes) {
289+
TransportAddress address = discoveryNode.getAddress();
290+
TransportAddress expected = poorMansDNS.get(discoveryNode.getName());
291+
assertEquals(address, expected);
292+
}
293+
}
294+
295+
262296
abstract class DummyEc2HostProvider extends AwsEc2UnicastHostsProvider {
263297
public int fetchCount = 0;
264298
public DummyEc2HostProvider(Settings settings, TransportService transportService, AwsEc2Service service) {

0 commit comments

Comments
 (0)