package core.aws.task.elb;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.ec2.model.Subnet;
import com.amazonaws.services.elasticloadbalancing.model.AccessLog;
import com.amazonaws.services.elasticloadbalancing.model.ConfigureHealthCheckRequest;
import com.amazonaws.services.elasticloadbalancing.model.ConnectionDraining;
import com.amazonaws.services.elasticloadbalancing.model.CreateLoadBalancerRequest;
import com.amazonaws.services.elasticloadbalancing.model.CrossZoneLoadBalancing;
import com.amazonaws.services.elasticloadbalancing.model.HealthCheck;
import com.amazonaws.services.elasticloadbalancing.model.Listener;
import com.amazonaws.services.elasticloadbalancing.model.LoadBalancerAttributes;
import com.amazonaws.services.elasticloadbalancing.model.ModifyLoadBalancerAttributesRequest;
import com.amazonaws.services.elasticloadbalancing.model.Tag;
import com.amazonaws.services.s3.model.SetBucketPolicyRequest;
import core.aws.client.AWS;
import core.aws.env.Context;
import core.aws.resource.elb.ELB;
import core.aws.workflow.Action;
import core.aws.workflow.Task;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author neo
*/
@Action("create-elb")
public class CreateELBTask extends Task<ELB> {
public CreateELBTask(ELB elb) {
super(elb);
}
@Override
public void execute(Context context) throws Exception {
CreateLoadBalancerRequest request = new CreateLoadBalancerRequest()
.withLoadBalancerName(resource.name)
.withScheme(resource.scheme.orElse(null))
.withTags(new Tag().withKey("cloud-manager:env").withValue(context.env.name));
if (resource.subnet != null) {
request.withSecurityGroups(resource.securityGroup.remoteSecurityGroup.getGroupId())
.withSubnets(resource.subnet.remoteSubnets.stream().map(Subnet::getSubnetId).collect(Collectors.toList()));
} else {
List<String> zones = AWS.ec2.availabilityZones();
request.withAvailabilityZones(zones.get(0));
}
if (resource.listenHTTP) {
request.getListeners().add(new Listener("HTTP", 80, 80));
}
if (resource.listenHTTPS) {
String certARN = resource.amazonCertARN != null ? resource.amazonCertARN : resource.cert.remoteCert.getServerCertificateMetadata().getArn();
request.getListeners().add(new Listener()
.withProtocol("HTTPS")
.withLoadBalancerPort(443)
.withInstanceProtocol("HTTP")
.withInstancePort(80)
.withSSLCertificateId(certARN));
}
resource.remoteELB = AWS.elb.createELB(request);
configureELB(context.env.region);
configureHealthCheck();
context.output(String.format("elb/%s/DNS", resource.id), resource.remoteELB.getDNSName());
}
private void configureELB(Regions region) {
LoadBalancerAttributes attributes = new LoadBalancerAttributes()
.withConnectionDraining(new ConnectionDraining().withEnabled(true).withTimeout(30));
// enable cross zone load balance for multi-az
if (resource.subnet != null && resource.subnet.cidrs.size() > 1) {
attributes.setCrossZoneLoadBalancing(new CrossZoneLoadBalancing().withEnabled(true));
}
if (resource.accessLogBucket != null) {
configureAccessLog(attributes, region);
}
AWS.elb.modifyELBAttributes(new ModifyLoadBalancerAttributesRequest()
.withLoadBalancerName(resource.name)
.withLoadBalancerAttributes(attributes));
}
private void configureAccessLog(LoadBalancerAttributes attributes, Regions region) {
ELBAccessLogBucketPolicyBuilder builder = new ELBAccessLogBucketPolicyBuilder();
String bucketName = resource.accessLogBucket.remoteBucket.getName();
AWS.s3.s3.setBucketPolicy(new SetBucketPolicyRequest(bucketName, builder.policyText(region, bucketName)));
attributes.withAccessLog(new AccessLog()
.withEnabled(true)
.withS3BucketName(bucketName)
.withS3BucketPrefix("elb/" + resource.id));
}
private void configureHealthCheck() {
// optimize for high load the instances take longer to response, especially in Multi-AZ,
// there are multiple ELB instances send health check requests same time
HealthCheck healthCheck = new HealthCheck()
.withHealthyThreshold(2)
.withUnhealthyThreshold(5)
.withInterval(20)
.withTimeout(15)
.withTarget("HTTP:80" + resource.healthCheckURL);
AWS.elb.elb.configureHealthCheck(new ConfigureHealthCheckRequest(resource.name, healthCheck));
}
}