package core.aws.client; import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancing; import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClientBuilder; import com.amazonaws.services.elasticloadbalancing.model.ApplySecurityGroupsToLoadBalancerRequest; import com.amazonaws.services.elasticloadbalancing.model.CreateLoadBalancerRequest; import com.amazonaws.services.elasticloadbalancing.model.DeleteLoadBalancerRequest; import com.amazonaws.services.elasticloadbalancing.model.DeregisterInstancesFromLoadBalancerRequest; import com.amazonaws.services.elasticloadbalancing.model.DescribeInstanceHealthRequest; import com.amazonaws.services.elasticloadbalancing.model.DescribeInstanceHealthResult; import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancersRequest; import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancersResult; import com.amazonaws.services.elasticloadbalancing.model.Instance; import com.amazonaws.services.elasticloadbalancing.model.InstanceState; import com.amazonaws.services.elasticloadbalancing.model.LoadBalancerDescription; import com.amazonaws.services.elasticloadbalancing.model.ModifyLoadBalancerAttributesRequest; import com.amazonaws.services.elasticloadbalancing.model.RegisterInstancesWithLoadBalancerRequest; import core.aws.util.Runner; import core.aws.util.Threads; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.time.Duration; import java.util.List; import java.util.stream.Collectors; /** * @author neo */ public class ElasticLoadBalancing { public final AmazonElasticLoadBalancing elb; private final Logger logger = LoggerFactory.getLogger(ElasticLoadBalancing.class); public ElasticLoadBalancing(AWSCredentialsProvider credentials, Regions region) { elb = AmazonElasticLoadBalancingClientBuilder.standard().withRegion(region).withCredentials(credentials).build(); } public LoadBalancerDescription createELB(final CreateLoadBalancerRequest request) throws Exception { new Runner<>() .retryInterval(Duration.ofSeconds(20)) .maxAttempts(5) .retryOn(e -> e instanceof AmazonServiceException) .run(() -> { logger.info("create elb, request={}", request); elb.createLoadBalancer(request); return null; }); return describeELB(request.getLoadBalancerName()); } public void modifyELBAttributes(ModifyLoadBalancerAttributesRequest request) { logger.info("modify elb attributes, request={}", request); elb.modifyLoadBalancerAttributes(request); } public LoadBalancerDescription describeELB(String elbName) { logger.info("describe elb, elbName={}", elbName); DescribeLoadBalancersResult result = elb.describeLoadBalancers(new DescribeLoadBalancersRequest() .withLoadBalancerNames(elbName)); return result.getLoadBalancerDescriptions().get(0); } public List<LoadBalancerDescription> listELBs() { logger.info("list all elbs"); DescribeLoadBalancersResult result = elb.describeLoadBalancers(); return result.getLoadBalancerDescriptions(); } public void deleteELB(String elbName) { logger.info("delete elb, elbName={}", elbName); elb.deleteLoadBalancer(new DeleteLoadBalancerRequest(elbName)); } public void updateELBSG(String elbName, String sgId) { logger.info("apply security group to elb, elbName={}, sgId={}", elbName, sgId); elb.applySecurityGroupsToLoadBalancer(new ApplySecurityGroupsToLoadBalancerRequest() .withLoadBalancerName(elbName) .withSecurityGroups(sgId)); } public List<InstanceState> describeInstanceHealth(String elbName, List<String> instanceIds) { logger.info("describe elb instance health, instanceIds={}", instanceIds); List<com.amazonaws.services.elasticloadbalancing.model.Instance> instances = instanceIds.stream() .map(com.amazonaws.services.elasticloadbalancing.model.Instance::new) .collect(Collectors.toList()); DescribeInstanceHealthResult result = elb.describeInstanceHealth(new DescribeInstanceHealthRequest(elbName) .withInstances(instances)); return result.getInstanceStates(); } public void detachInstances(String elbName, List<String> instanceIds) { logger.info("detach instances from elb, elb={}, instances={}", elbName, instanceIds); List<Instance> instances = instanceIds.stream().map(Instance::new).collect(Collectors.toList()); elb.deregisterInstancesFromLoadBalancer(new DeregisterInstancesFromLoadBalancerRequest() .withLoadBalancerName(elbName) .withInstances(instances)); } public void attachInstances(String elbName, List<String> instanceIds, boolean waitUntilInService) throws InterruptedException { logger.info("attach instances to elb, elb={}, instances={}", elbName, instanceIds); String expectedState = waitUntilInService ? "InService" : "Service"; // if not waitUntilInService, state can be InService or OutOfService List<Instance> instances = instanceIds.stream().map(Instance::new).collect(Collectors.toList()); elb.registerInstancesWithLoadBalancer(new RegisterInstancesWithLoadBalancerRequest() .withLoadBalancerName(elbName) .withInstances(instances)); int attempts = 0; while (true) { attempts++; Threads.sleepRoughly(Duration.ofSeconds(15)); List<InstanceState> states = describeInstanceHealth(elbName, instanceIds); for (InstanceState state : states) { logger.info("instance elb state {} => {}", state.getInstanceId(), state.getState()); } boolean allAttached = states.stream().allMatch(state -> state.getState().contains(expectedState)); if (allAttached) { logger.info("all instances are attached to elb"); break; } else if (attempts >= 30) { throw new Error("failed to wait all instances to be attached to elb, please check aws console for more details"); } else { logger.info("continue to wait, not all new instances are attached"); } } } }