Skip to content

Commit 712baa4

Browse files
joeslicedadoonet
authored andcommitted
Filter instances using EC2 API instead of locally
This change will allow EC2 API to filter by tags, AZ, and instance state. In the situation where you have a large number of instances/reservations, this can be a performance boost. Note that we still do the security group filter locally due to the different strategies (all or some must match). Closes elastic#39.
1 parent 283d174 commit 712baa4

File tree

1 file changed

+53
-64
lines changed

1 file changed

+53
-64
lines changed

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

Lines changed: 53 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ public List<DiscoveryNode> buildDynamicNodes() {
9999

100100
DescribeInstancesResult descInstances;
101101
try {
102-
descInstances = client.describeInstances(new DescribeInstancesRequest());
102+
// Query EC2 API based on AZ, instance state, and tag.
103+
104+
// NOTE: we don't filter by security group during the describe instances request for two reasons:
105+
// 1. differences in VPCs require different parameters during query (ID vs Name)
106+
// 2. We want to use two different strategies: (all security groups vs. any security groups)
107+
descInstances = client.describeInstances(buildDescribeInstancesRequest());
103108
} catch (AmazonClientException e) {
104109
logger.info("Exception while retrieving instance list from AWS API: {}", e.getMessage());
105110
logger.debug("Full exception:", e);
@@ -109,13 +114,6 @@ public List<DiscoveryNode> buildDynamicNodes() {
109114
logger.trace("building dynamic unicast discovery nodes...");
110115
for (Reservation reservation : descInstances.getReservations()) {
111116
for (Instance instance : reservation.getInstances()) {
112-
if (!availabilityZones.isEmpty()) {
113-
if (!availabilityZones.contains(instance.getPlacement().getAvailabilityZone())) {
114-
logger.trace("filtering out instance {} based on availability_zone {}, not part of {}", instance.getInstanceId(), instance.getPlacement().getAvailabilityZone(), availabilityZones);
115-
continue;
116-
}
117-
}
118-
119117
// lets see if we can filter based on groups
120118
if (!groups.isEmpty()) {
121119
List<GroupIdentifier> instanceSecurityGroups = instance.getSecurityGroups();
@@ -138,66 +136,34 @@ public List<DiscoveryNode> buildDynamicNodes() {
138136
}
139137
}
140138

141-
// see if we need to filter by tags
142-
boolean filterByTag = false;
143-
if (!tags.isEmpty()) {
144-
if (instance.getTags() == null) {
145-
filterByTag = true;
146-
} else {
147-
// check that all tags listed are there on the instance
148-
for (Map.Entry<String, String> entry : tags.entrySet()) {
149-
boolean found = false;
150-
for (Tag tag : instance.getTags()) {
151-
if (entry.getKey().equals(tag.getKey()) && entry.getValue().equals(tag.getValue())) {
152-
found = true;
153-
break;
154-
}
155-
}
156-
if (!found) {
157-
filterByTag = true;
158-
break;
159-
}
160-
}
161-
}
139+
String address = null;
140+
switch (hostType) {
141+
case PRIVATE_DNS:
142+
address = instance.getPrivateDnsName();
143+
break;
144+
case PRIVATE_IP:
145+
address = instance.getPrivateIpAddress();
146+
break;
147+
case PUBLIC_DNS:
148+
address = instance.getPublicDnsName();
149+
break;
150+
case PUBLIC_IP:
151+
address = instance.getPublicDnsName();
152+
break;
162153
}
163-
if (filterByTag) {
164-
logger.trace("filtering out instance {} based tags {}, not part of {}", instance.getInstanceId(), tags, instance.getTags());
165-
continue;
166-
}
167-
168-
InstanceState state = instance.getState();
169-
if (state.getName().equalsIgnoreCase("pending") || state.getName().equalsIgnoreCase("running")) {
170-
String address = null;
171-
switch (hostType) {
172-
case PRIVATE_DNS:
173-
address = instance.getPrivateDnsName();
174-
break;
175-
case PRIVATE_IP:
176-
address = instance.getPrivateIpAddress();
177-
break;
178-
case PUBLIC_DNS:
179-
address = instance.getPublicDnsName();
180-
break;
181-
case PUBLIC_IP:
182-
address = instance.getPublicDnsName();
183-
break;
184-
}
185-
if (address != null) {
186-
try {
187-
TransportAddress[] addresses = transportService.addressesFromString(address);
188-
// we only limit to 1 address, makes no sense to ping 100 ports
189-
for (int i = 0; (i < addresses.length && i < UnicastZenPing.LIMIT_PORTS_COUNT); i++) {
190-
logger.trace("adding {}, address {}, transport_address {}", instance.getInstanceId(), address, addresses[i]);
191-
discoNodes.add(new DiscoveryNode("#cloud-" + instance.getInstanceId() + "-" + i, addresses[i], Version.CURRENT));
192-
}
193-
} catch (Exception e) {
194-
logger.warn("failed to add {}, address {}", e, instance.getInstanceId(), address);
154+
if (address != null) {
155+
try {
156+
TransportAddress[] addresses = transportService.addressesFromString(address);
157+
// we only limit to 1 addresses, makes no sense to ping 100 ports
158+
for (int i = 0; (i < addresses.length && i < UnicastZenPing.LIMIT_PORTS_COUNT); i++) {
159+
logger.trace("adding {}, address {}, transport_address {}", instance.getInstanceId(), address, addresses[i]);
160+
discoNodes.add(new DiscoveryNode("#cloud-" + instance.getInstanceId() + "-" + i, addresses[i], Version.CURRENT));
195161
}
196-
} else {
197-
logger.trace("not adding {}, address is null, host_type {}", instance.getInstanceId(), hostType);
162+
} catch (Exception e) {
163+
logger.warn("failed ot add {}, address {}", e, instance.getInstanceId(), address);
198164
}
199165
} else {
200-
logger.trace("not adding {}, state {} is not pending or running", instance.getInstanceId(), state.getName());
166+
logger.trace("not adding {}, address is null, host_type {}", instance.getInstanceId(), hostType);
201167
}
202168
}
203169
}
@@ -206,4 +172,27 @@ public List<DiscoveryNode> buildDynamicNodes() {
206172

207173
return discoNodes;
208174
}
175+
176+
private DescribeInstancesRequest buildDescribeInstancesRequest() {
177+
DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest()
178+
.withFilters(
179+
new Filter("instance-state-name").withValues("running", "pending")
180+
);
181+
182+
for (Map.Entry<String, String> tagFilter : tags.entrySet()) {
183+
// for a given tag key, OR relationship for multiple different values
184+
describeInstancesRequest.withFilters(
185+
new Filter("tag:" + tagFilter.getKey()).withValues(tagFilter.getValue())
186+
);
187+
}
188+
189+
if (!availabilityZones.isEmpty()) {
190+
// OR relationship amongst multiple values of the availability-zone filter
191+
describeInstancesRequest.withFilters(
192+
new Filter("availability-zone").withValues(availabilityZones)
193+
);
194+
}
195+
196+
return describeInstancesRequest;
197+
}
209198
}

0 commit comments

Comments
 (0)