blob: 7a7891d10d89bda2827912379b62bffb3afd3af6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.ignite.spi.discovery.tcp.ipfinder.elb;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancing;
import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClientBuilder;
import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancersRequest;
import com.amazonaws.services.elasticloadbalancing.model.Instance;
import com.amazonaws.services.elasticloadbalancing.model.LoadBalancerDescription;
import org.apache.ignite.spi.IgniteSpiConfiguration;
import org.apache.ignite.spi.IgniteSpiException;
import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinderAdapter;
import static com.amazonaws.util.StringUtils.isNullOrEmpty;
/**
* AWS Classic load balancer based IP finder.
*
* <p>
* For information about Amazon Classic load balancers visit:
* <a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/introduction.html">aws.amazon.com</a>.
* </p>
*
* <h1 class="header">Configuration</h1>
* <h2 class="header">Mandatory</h2>
* <ul>
* <li>{@link #setCredentialsProvider(AWSCredentialsProvider)}</li>
* <li>Classic load balancer name (see {@link #setLoadBalancerName(String)})</li>
* <li>Classic load balancer region (see {@link #setRegion(String)})</li>
* </ul>
*
* <p> The finder will fetch all nodes connected under an Classic load balancer and share with its peers for cluster
* awareness.</p>
*
* <p> Note that using AWS Classic load balancer service will result in charges to your AWS account.</p>
*
* <p>
* Choose another implementation of {@link org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder}
* for local or home network tests.</p>
*
* <p> Note that this finder is shared.</p>
*
* <p> Note that this finder can only be used on AWS EC2 instances that belong on a Load Balancer based auto scaling group.</p>
*
* @see TcpDiscoveryAlbIpFinder
*/
public class TcpDiscoveryElbIpFinder extends TcpDiscoveryIpFinderAdapter {
/** */
private AmazonElasticLoadBalancing amazonELBClient;
/** */
private AmazonEC2 amazonEC2Client;
/** */
private AWSCredentialsProvider credsProvider;
/** */
private String region;
/** */
private String loadBalancerName;
/**
* Creates Classic load balancer IP finder instance.
*/
public TcpDiscoveryElbIpFinder() {
setShared(true);
}
/** {@inheritDoc} */
@Override public Collection<InetSocketAddress> getRegisteredAddresses() throws IgniteSpiException {
initClients();
List<String> instanceIds = new ArrayList<>();
DescribeLoadBalancersRequest req = new DescribeLoadBalancersRequest().withLoadBalancerNames(loadBalancerName);
List<LoadBalancerDescription> descs = amazonELBClient.describeLoadBalancers(req).getLoadBalancerDescriptions();
for (LoadBalancerDescription desc : descs) {
for (Instance instance : desc.getInstances())
instanceIds.add(instance.getInstanceId());
}
DescribeInstancesRequest instReq = new DescribeInstancesRequest().withInstanceIds(instanceIds);
List<Reservation> reservations = amazonEC2Client.describeInstances(instReq).getReservations();
List<InetSocketAddress> addrs = new ArrayList<>();
for (Reservation reservation : reservations) {
List<com.amazonaws.services.ec2.model.Instance> instances = reservation.getInstances();
for (com.amazonaws.services.ec2.model.Instance instance : instances)
addrs.add(new InetSocketAddress(instance.getPrivateIpAddress(), 0));
}
return addrs;
}
/**
* Initializing the IP finder.
*/
private void initClients() {
if (credsProvider == null || isNullOrEmpty(loadBalancerName) || isNullOrEmpty(region))
throw new IgniteSpiException("One or more configuration parameters are invalid [setCredentialsProvider=" +
credsProvider + ", setRegion=" + region + ", setLoadBalancerName=" +
loadBalancerName + "]");
if (amazonEC2Client == null)
amazonEC2Client = AmazonEC2ClientBuilder.standard().withRegion(region).withCredentials(credsProvider)
.build();
if (amazonELBClient == null)
amazonELBClient = AmazonElasticLoadBalancingClientBuilder.standard().withRegion(region)
.withCredentials(credsProvider).build();
}
/**
* Sets AWS Classic load balancer name which nodes are plugged under it. For details refer to Amazon API
* reference.
*
* @param loadBalancerName AWS Classic load balancer name.
*/
@IgniteSpiConfiguration(optional = false)
public void setLoadBalancerName(String loadBalancerName) {
this.loadBalancerName = loadBalancerName;
}
/**
* Sets Classic load balancer's region.
*
* For details refer to Amazon API reference.
*
* @param region AWS Classic load balancer region (i.e: us-east-1)
*/
@IgniteSpiConfiguration(optional = false)
public void setRegion(String region) {
this.region = region;
}
/**
* Sets AWS credentials provider.
*
* For details refer to Amazon API reference.
*
* @param credsProvider AWS credentials provider.
*/
@IgniteSpiConfiguration(optional = false)
public void setCredentialsProvider(AWSCredentialsProvider credsProvider) {
this.credsProvider = credsProvider;
}
/** {@inheritDoc} */
@Override public void registerAddresses(Collection<InetSocketAddress> addrs) throws IgniteSpiException {
//No-op, Classic load balancer will take care of registration.
}
/** {@inheritDoc} */
@Override public void unregisterAddresses(Collection<InetSocketAddress> addrs) throws IgniteSpiException {
// No-op, Classic load balancer will take care of this process.
}
}