All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.polyglotted.common.es.discovery.Ec2HostsProvider Maven / Gradle / Ivy

package io.polyglotted.common.es.discovery;

import com.amazonaws.AmazonClientException;
import com.amazonaws.http.IdleConnectionReaper;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.model.*;
import io.polyglotted.applauncher.settings.SettingsHolder;
import io.polyglotted.common.es.discovery.Ec2Service.DISCOVERY_EC2;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.common.settings.Settings;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.google.common.collect.Sets.newHashSet;
import static io.polyglotted.common.es.discovery.Ec2Service.DISCOVERY_EC2.HostType.*;
import static java.util.Collections.disjoint;

@Slf4j
public final class Ec2HostsProvider implements Closeable {
    private final AmazonEC2 client;
    private final boolean bindAnyGroup;
    private final Set groups;
    private final Map tags;
    private final Set availabilityZones;
    private final String hostType;

    public static List fetchEc2Addresses(Settings settings) throws IOException {
        try (Ec2HostsProvider provider = new Ec2HostsProvider(settings)) { return provider.fetchAddresses(); }
    }

    private Ec2HostsProvider(Settings settings) {
        this.client = Ec2ServiceImpl.client(settings);
        this.hostType = DISCOVERY_EC2.HOST_TYPE_SETTING.get(settings);
        this.bindAnyGroup = DISCOVERY_EC2.ANY_GROUP_SETTING.get(settings);
        this.groups = newHashSet(DISCOVERY_EC2.GROUPS_SETTING.get(settings));
        this.tags = DISCOVERY_EC2.TAG_SETTING.get(settings).getAsMap();
        this.availabilityZones = newHashSet(DISCOVERY_EC2.AVAILABILITY_ZONES_SETTING.get(settings));
        if (log.isDebugEnabled()) {
            log.debug("using host_type [{}], tags [{}], groups [{}] with any_group [{}], availability_zones [{}]",
                hostType, tags, groups, bindAnyGroup, availabilityZones);
        }
    }

    @Override
    public void close() throws IOException {
        if (client != null) { client.shutdown(); }
        IdleConnectionReaper.shutdown();
    }

    private List fetchAddresses() {
        List addresses = new ArrayList<>();
        DescribeInstancesResult descInstances;
        try {
            descInstances = client.describeInstances(buildDescribeInstancesRequest());
        } catch (AmazonClientException e) {
            log.info("Exception while retrieving instance list from AWS API: {}", e.getMessage());
            log.debug("Full exception:", e);
            return addresses;
        }

        log.trace("building dynamic unicast discovery nodes...");
        for (Reservation reservation : descInstances.getReservations()) {
            for (Instance instance : reservation.getInstances()) {
                if (!groups.isEmpty()) {
                    List instanceSecurityGroups = instance.getSecurityGroups();
                    List securityGroupNames = new ArrayList<>(instanceSecurityGroups.size());
                    List securityGroupIds = new ArrayList<>(instanceSecurityGroups.size());
                    for (GroupIdentifier sg : instanceSecurityGroups) {
                        securityGroupNames.add(sg.getGroupName());
                        securityGroupIds.add(sg.getGroupId());
                    }
                    if (bindAnyGroup) {
                        if (disjoint(securityGroupNames, groups) && disjoint(securityGroupIds, groups)) {
                            log.trace("filtering out instance {} based on groups {}, not part of {}", instance.getInstanceId(),
                                instanceSecurityGroups, groups);
                            continue;
                        }
                    }
                    else {
                        if (!(securityGroupNames.containsAll(groups) || securityGroupIds.containsAll(groups))) {
                            log.trace("filtering out instance {} based on groups {}, does not include all of {}",
                                instance.getInstanceId(), instanceSecurityGroups, groups);
                            continue;
                        }
                    }
                }

                String address = null;
                if (hostType.equals(PRIVATE_DNS)) { address = instance.getPrivateDnsName(); }
                else if (hostType.equals(PRIVATE_IP)) { address = instance.getPrivateIpAddress(); }
                else if (hostType.equals(PUBLIC_DNS)) { address = instance.getPublicDnsName(); }
                else if (hostType.equals(PUBLIC_IP)) { address = instance.getPublicIpAddress(); }
                else if (hostType.startsWith(TAG_PREFIX)) {
                    String tagName = hostType.substring(TAG_PREFIX.length());
                    log.debug("reading hostname from [{}] instance tag", tagName);
                    List tags = instance.getTags();
                    for (Tag tag : tags) {
                        if (tag.getKey().equals(tagName)) { address = tag.getValue(); log.debug("using [{}] as the instance address", address); }
                    }
                }
                else {
                    throw new IllegalArgumentException(hostType + " is unknown for discovery.ec2.host_type");
                }
                if (address != null) { addresses.add(address); }
            }
        }
        log.debug("using dynamic discovery addresses {}", addresses);
        return addresses;
    }

    private DescribeInstancesRequest buildDescribeInstancesRequest() {
        DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest()
            .withFilters(new Filter("instance-state-name").withValues("running", "pending"));
        for (Map.Entry tagFilter : tags.entrySet()) {
            describeInstancesRequest.withFilters(new Filter("tag:" + tagFilter.getKey()).withValues(tagFilter.getValue()));
        }
        if (!availabilityZones.isEmpty()) {
            describeInstancesRequest.withFilters(new Filter("availability-zone").withValues(availabilityZones));
        }
        return describeInstancesRequest;
    }

    public static Settings buildSettings(SettingsHolder settingsHolder) {
        Settings.Builder builder = Settings.builder();
        for (Map.Entry e : settingsHolder.asProperties("es", false).entrySet()) {
            builder.put(e.getKey(), String.valueOf(e.getValue()));
        }
        return builder.build();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy