mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-24 14:38:45 +00:00
bug4811: Builder pattern for load balancer-related procedures; updated tests accordingly
This commit is contained in:
+27
@@ -21,9 +21,11 @@ import com.sap.sailing.landscape.procedures.StartSailingAnalyticsMaster;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.landscape.InboundReplicationConfiguration;
|
||||
import com.sap.sse.landscape.aws.AwsInstance;
|
||||
import com.sap.sse.landscape.aws.AwsLandscape;
|
||||
import com.sap.sse.landscape.aws.Tags;
|
||||
import com.sap.sse.landscape.aws.impl.AwsRegion;
|
||||
import com.sap.sse.landscape.aws.orchestration.CreateDynamicLoadBalancerMapping;
|
||||
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.ec2.model.Instance;
|
||||
@@ -103,6 +105,31 @@ public class TestProcedures {
|
||||
assertFalse(envSh.isEmpty());
|
||||
assertTrue("Couldn't find SERVER_NAME=\""+serverName+"\" in env.sh:\n"+envSh, envSh.contains("SERVER_NAME=\""+serverName+"\""));
|
||||
assertEquals(14888, process.getTelnetPortToOSGiConsole(optionalTimeout));
|
||||
// Now create an ALB mapping, assuming to create the dynamic ALB:
|
||||
final String domain = "wiesen-weg.de";
|
||||
final String hostname = serverName+"."+domain;
|
||||
CreateDynamicLoadBalancerMapping.Builder<String, SailingAnalyticsMetrics,
|
||||
SailingAnalyticsMaster<String>, SailingAnalyticsReplica<String>, AwsInstance<String, SailingAnalyticsMetrics>> createAlbProcedureBuilder = CreateDynamicLoadBalancerMapping.builder();
|
||||
createAlbProcedureBuilder
|
||||
.setProcess(process)
|
||||
.setHostname(hostname)
|
||||
.setTargetGroupNamePrefix("S-ded-") // TODO when we combine procedures for launching dedicated hosts (StartSailingAnlayticsHost and specializations) then "S-ded-" should be the default; for DeployProcessOnMultiServer, "S-shared-" should be the default
|
||||
.setLandscape(landscape);
|
||||
optionalTimeout.ifPresent(createAlbProcedureBuilder::setTimeout);
|
||||
final CreateDynamicLoadBalancerMapping<String, SailingAnalyticsMetrics, SailingAnalyticsMaster<String>, SailingAnalyticsReplica<String>, AwsInstance<String, SailingAnalyticsMetrics>> createAlbProcedure =
|
||||
createAlbProcedureBuilder.build();
|
||||
try {
|
||||
createAlbProcedure.run();
|
||||
// A few validations:
|
||||
// Is the process's host part of the public and master target groups?
|
||||
assertNotNull(createAlbProcedure.getMasterTargetGroupCreated());
|
||||
assertNotNull(createAlbProcedure.getPublicTargetGroupCreated());
|
||||
assertTrue(createAlbProcedure.getMasterTargetGroupCreated().getRegisteredTargets().keySet().contains(process.getHost()));
|
||||
assertTrue(createAlbProcedure.getPublicTargetGroupCreated().getRegisteredTargets().keySet().contains(process.getHost()));
|
||||
} finally {
|
||||
landscape.deleteLoadBalancer(createAlbProcedure.getLoadBalancerUsed());
|
||||
landscape.removeDNSRecord(landscape.getDNSHostedZoneId(domain), hostname, "*."+domain);
|
||||
}
|
||||
} finally {
|
||||
landscape.terminate(host);
|
||||
landscape.deleteKeyPair(region, keyName);
|
||||
|
||||
+9
-4
@@ -40,7 +40,6 @@ import com.sap.sse.landscape.application.impl.ApplicationProcessImpl;
|
||||
import com.sap.sse.landscape.aws.impl.AmazonMachineImage;
|
||||
import com.sap.sse.landscape.aws.impl.AwsRegion;
|
||||
import com.sap.sse.landscape.aws.orchestration.CreateDNSBasedLoadBalancerMapping;
|
||||
import com.sap.sse.landscape.aws.orchestration.CreateLoadBalancerMapping;
|
||||
import com.sap.sse.landscape.impl.ReleaseRepositoryImpl;
|
||||
import com.sap.sse.landscape.ssh.SSHKeyPair;
|
||||
import com.sap.sse.landscape.ssh.SshCommandChannel;
|
||||
@@ -115,9 +114,15 @@ public class ConnectivityTest {
|
||||
assertEquals(14888, process.getTelnetPortToOSGiConsole(optionalTimeout));
|
||||
@SuppressWarnings("unchecked")
|
||||
final AwsLandscape<String, ApplicationProcessMetrics, MasterT, ReplicaT> castLandscape = (AwsLandscape<String, ApplicationProcessMetrics, MasterT, ReplicaT>) landscape;
|
||||
final CreateLoadBalancerMapping<String, ApplicationProcessMetrics, MasterT, ReplicaT, AwsInstance<String, ApplicationProcessMetrics>> createDNSBasedLoadBalancerMappingProcedure =
|
||||
new CreateDNSBasedLoadBalancerMapping<String, ApplicationProcessMetrics, MasterT, ReplicaT, AwsInstance<String, ApplicationProcessMetrics>>(
|
||||
process, hostname, TARGET_GROUP_NAME_PREFIX, castLandscape, optionalTimeout);
|
||||
final CreateDNSBasedLoadBalancerMapping.Builder<String, ApplicationProcessMetrics, MasterT, ReplicaT, AwsInstance<String, ApplicationProcessMetrics>> builder = CreateDNSBasedLoadBalancerMapping.builder();
|
||||
builder
|
||||
.setProcess(process)
|
||||
.setHostname(hostname)
|
||||
.setTargetGroupNamePrefix(TARGET_GROUP_NAME_PREFIX)
|
||||
.setLandscape(castLandscape);
|
||||
optionalTimeout.ifPresent(builder::setTimeout);
|
||||
final CreateDNSBasedLoadBalancerMapping<String, ApplicationProcessMetrics, MasterT, ReplicaT, AwsInstance<String, ApplicationProcessMetrics>> createDNSBasedLoadBalancerMappingProcedure =
|
||||
builder.build();
|
||||
final String wiesenWegId = landscape.getDNSHostedZoneId(hostedZoneName);
|
||||
try {
|
||||
createDNSBasedLoadBalancerMappingProcedure.run();
|
||||
|
||||
@@ -207,6 +207,8 @@ extends Landscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
|
||||
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> getLoadBalancer(String loadBalancerArn, Region region);
|
||||
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> getLoadBalancerByName(String name, Region region);
|
||||
|
||||
/**
|
||||
* Creates an application load balancer with the name and in the region specified. The method returns once the request
|
||||
* has been responded to. The load balancer may still be in a pre-ready state. Use {@link #getApplicationLoadBalancerStatus(ApplicationLoadBalancer)}
|
||||
|
||||
+17
-6
@@ -103,6 +103,7 @@ import software.amazon.awssdk.services.elasticloadbalancingv2.model.DescribeTarg
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.Listener;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.LoadBalancer;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.LoadBalancerAttribute;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.LoadBalancerNotFoundException;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.LoadBalancerState;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.ModifyTargetGroupAttributesRequest;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.ProtocolEnum;
|
||||
@@ -130,6 +131,7 @@ import software.amazon.awssdk.services.route53.model.ResourceRecordSet;
|
||||
public class AwsLandscapeImpl<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>> implements AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
|
||||
private static final String DEFAULT_TARGET_GROUP_PREFIX = "D";
|
||||
private static final Logger logger = Logger.getLogger(AwsLandscapeImpl.class.getName());
|
||||
private static final long DEFAULT_DNS_TTL_MILLIS = 60000l;
|
||||
// TODO <config> the sapsailing.com certificate's ARN where the certificate is valid until 2021-05-07; we need a certifiate per region
|
||||
@@ -137,7 +139,7 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
|
||||
// TODO <config> the "Java Application with Reverse Proxy" security group in eu-west-2 for experimenting; we need this security group per region
|
||||
private static final String DEFAULT_APPLICATION_SERVER_SECURITY_GROUP_ID_EU_WEST_1 = "sg-eaf31e85";
|
||||
private static final String DEFAULT_APPLICATION_SERVER_SECURITY_GROUP_ID_EU_WEST_2 = "sg-0b2afd48960251280";
|
||||
private static final String DEFAULT_NON_DNS_MAPPED_ALB_NAME = "DefaultDynamicALB";
|
||||
private static final String DEFAULT_NON_DNS_MAPPED_ALB_NAME = "DefDyn";
|
||||
private static final String MONGO_REPLICA_SET_TAG_NAME = "mongo-replica-set";
|
||||
private static final String MONGO_DEFAULT_REPLICA_SET_NAME = "live";
|
||||
private static final String RABBITMQ_TAG_NAME = "RabbitMQEndpoint";
|
||||
@@ -252,7 +254,7 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
|
||||
private Listener createLoadBalancerListener(ApplicationLoadBalancer<ShardingKey, MetricsT> alb, ProtocolEnum protocol) {
|
||||
final int port = protocol==ProtocolEnum.HTTP?80:443;
|
||||
final ReverseProxyCluster<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, RotatingFileBasedLog> reverseProxy = getCentralReverseProxy(alb.getRegion());
|
||||
final TargetGroup<ShardingKey, MetricsT> defaultTargetGroup = createTargetGroup(alb.getRegion(), "DefTG-"+alb.getName()+"-"+protocol.name(),
|
||||
final TargetGroup<ShardingKey, MetricsT> defaultTargetGroup = createTargetGroup(alb.getRegion(), DEFAULT_TARGET_GROUP_PREFIX+alb.getName()+"-"+protocol.name(),
|
||||
port, reverseProxy.getHealthCheckPath(), /* healthCheckPort */ port);
|
||||
defaultTargetGroup.addTargets(reverseProxy.getHosts());
|
||||
return getLoadBalancingClient(
|
||||
@@ -360,6 +362,16 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationLoadBalancer<ShardingKey, MetricsT> getLoadBalancerByName(String name, com.sap.sse.landscape.Region region) {
|
||||
try {
|
||||
final DescribeLoadBalancersResponse response = getLoadBalancingClient(getRegion(region)).describeLoadBalancers(b->b.names(name));
|
||||
return response.hasLoadBalancers() ? new ApplicationLoadBalancerImpl<>(region, response.loadBalancers().iterator().next(), this) : null;
|
||||
} catch (LoadBalancerNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationLoadBalancer<ShardingKey, MetricsT> getLoadBalancer(String loadBalancerArn, com.sap.sse.landscape.Region region) {
|
||||
final LoadBalancer loadBalancer = getLoadBalancingClient(getRegion(region))
|
||||
@@ -735,8 +747,7 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
|
||||
@Override
|
||||
public ApplicationLoadBalancer<ShardingKey, MetricsT> getNonDNSMappedLoadBalancer(
|
||||
com.sap.sse.landscape.Region region, String wildcardDomain) {
|
||||
final DescribeLoadBalancersResponse response = getLoadBalancingClient(getRegion(region)).describeLoadBalancers(b->b.names(getNonDNSMappedLoadBalancerName(wildcardDomain)));
|
||||
return response.hasLoadBalancers() ? new ApplicationLoadBalancerImpl<>(region, response.loadBalancers().iterator().next(), this) : null;
|
||||
return getLoadBalancerByName(getNonDNSMappedLoadBalancerName(wildcardDomain), region);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -746,13 +757,13 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
|
||||
}
|
||||
|
||||
private String getNonDNSMappedLoadBalancerName(String wildcardDomain) {
|
||||
return DEFAULT_NON_DNS_MAPPED_ALB_NAME + "-" + wildcardDomain.replaceAll(".", "-");
|
||||
return DEFAULT_NON_DNS_MAPPED_ALB_NAME + wildcardDomain.replaceAll("\\.", "-");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationLoadBalancer<ShardingKey, MetricsT> getDNSMappedLoadBalancerFor(
|
||||
com.sap.sse.landscape.Region region, String hostname) {
|
||||
final DescribeLoadBalancersResponse response = getLoadBalancingClient(getRegion(region)).describeLoadBalancers(b->b.names(DEFAULT_NON_DNS_MAPPED_ALB_NAME));
|
||||
final DescribeLoadBalancersResponse response = getLoadBalancingClient(getRegion(region)).describeLoadBalancers();
|
||||
for (final LoadBalancer lb : response.loadBalancers()) {
|
||||
final ApplicationLoadBalancer<ShardingKey, MetricsT> alb = new ApplicationLoadBalancerImpl<>(region, lb, this);
|
||||
for (final Rule rule : alb.getRules()) {
|
||||
|
||||
+80
-50
@@ -2,7 +2,6 @@ package com.sap.sse.landscape.aws.orchestration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -10,7 +9,7 @@ import java.util.stream.IntStream;
|
||||
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.SftpException;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.landscape.Region;
|
||||
import com.sap.sse.landscape.application.ApplicationMasterProcess;
|
||||
@@ -36,65 +35,96 @@ import software.amazon.awssdk.services.elasticloadbalancingv2.model.LoadBalancer
|
||||
*/
|
||||
public class CreateDNSBasedLoadBalancerMapping<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
extends CreateLoadBalancerMapping<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, AwsInstance<ShardingKey, MetricsT>>
|
||||
implements Procedure<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
|
||||
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
extends CreateLoadBalancerMapping<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT>
|
||||
implements Procedure<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
|
||||
private static final String DNS_MAPPED_ALB_NAME_PREFIX = "DNSMapped-";
|
||||
private static final Pattern ALB_NAME_PATTERN = Pattern.compile(DNS_MAPPED_ALB_NAME_PREFIX+"(.*)$");
|
||||
|
||||
public CreateDNSBasedLoadBalancerMapping(
|
||||
ApplicationProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> process, String hostname,
|
||||
String targetGroupNamePrefix,
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape,
|
||||
Optional<Duration> optionalTimeout) throws JSchException, IOException, InterruptedException, SftpException {
|
||||
super(process, getOrCreateDNSMappedLoadBalancer(landscape, process.getHost().getRegion()), hostname,
|
||||
targetGroupNamePrefix, landscape, optionalTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds or creates a {@link ApplicationLoadBalander} load balancer in the {@code region} that is DNS-mapped and still has
|
||||
* at least the length of {@link #createRules()} additional rules available.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private static <ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
public static interface Builder<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> getOrCreateDNSMappedLoadBalancer(
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape, Region region) throws InterruptedException {
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> result = null;
|
||||
final Set<String> loadBalancerNames = new HashSet<>();
|
||||
for (final ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancer : landscape.getLoadBalancers(region)) {
|
||||
if (ALB_NAME_PATTERN.matcher(loadBalancer.getName()).matches()) {
|
||||
loadBalancerNames.add(loadBalancer.getName());
|
||||
if (Util.size(loadBalancer.getRules()) <= MAX_RULES_PER_ALB - NUMBER_OF_RULES_PER_REPLICA_SET) {
|
||||
result = loadBalancer;
|
||||
break;
|
||||
extends CreateLoadBalancerMapping.Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> {
|
||||
CreateDNSBasedLoadBalancerMapping<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> build() throws JSchException, IOException, InterruptedException, SftpException;
|
||||
}
|
||||
|
||||
protected static class BuilderImpl<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
extends CreateLoadBalancerMapping.BuilderImpl<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT>
|
||||
implements Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> {
|
||||
@Override
|
||||
public ApplicationLoadBalancer<ShardingKey, MetricsT> getLoadBalancerUsed() throws InterruptedException {
|
||||
final ApplicationLoadBalancer<ShardingKey, MetricsT> result;
|
||||
if (super.getLoadBalancerUsed() != null) {
|
||||
result = super.getLoadBalancerUsed();
|
||||
} else {
|
||||
result = getOrCreateDNSMappedLoadBalancer(getLandscape(), getProcess().getHost().getRegion());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds or creates a {@link ApplicationLoadBalander} load balancer in the {@code region} that is DNS-mapped and still has
|
||||
* at least the length of {@link #createRules()} additional rules available.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private ApplicationLoadBalancer<ShardingKey, MetricsT> getOrCreateDNSMappedLoadBalancer(
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape, Region region) throws InterruptedException {
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> result = null;
|
||||
final Set<String> loadBalancerNames = new HashSet<>();
|
||||
for (final ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancer : landscape.getLoadBalancers(region)) {
|
||||
if (ALB_NAME_PATTERN.matcher(loadBalancer.getName()).matches()) {
|
||||
loadBalancerNames.add(loadBalancer.getName());
|
||||
if (Util.size(loadBalancer.getRules()) <= MAX_RULES_PER_ALB - NUMBER_OF_RULES_PER_REPLICA_SET) {
|
||||
result = loadBalancer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
result = landscape.createLoadBalancer(getAvailableDNSMappedAlbName(loadBalancerNames), region);
|
||||
while (landscape.getApplicationLoadBalancerStatus(result).code() == LoadBalancerStateEnum.PROVISIONING) {
|
||||
Thread.sleep(1000); // wait until the ALB has been provisioned or failed
|
||||
if (result == null) {
|
||||
result = landscape.createLoadBalancer(getAvailableDNSMappedAlbName(loadBalancerNames), region);
|
||||
final TimePoint startingToPollForReady = TimePoint.now();
|
||||
while (landscape.getApplicationLoadBalancerStatus(result).code() == LoadBalancerStateEnum.PROVISIONING
|
||||
&& (!getOptionalTimeout().isPresent() || startingToPollForReady.until(TimePoint.now()).compareTo(getOptionalTimeout().get()) <= 0)) {
|
||||
Thread.sleep(1000); // wait until the ALB has been provisioned or failed
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
|
||||
/**
|
||||
* Picks a new load balancer name following the pattern {@link #DNS_MAPPED_ALB_NAME_PREFIX}{@code [0-9]+} that is not
|
||||
* part of {@code loadBalancerNames} and has the least number.
|
||||
*/
|
||||
private String getAvailableDNSMappedAlbName(Set<String> loadBalancerNames) {
|
||||
final Set<Integer> numbersTaken = new HashSet<>();
|
||||
for (final String loadBalancerName : loadBalancerNames) {
|
||||
final Matcher matcher = ALB_NAME_PATTERN.matcher(loadBalancerName);
|
||||
if (matcher.find()) {
|
||||
numbersTaken.add(Integer.parseInt(matcher.group(1)));
|
||||
}
|
||||
}
|
||||
return DNS_MAPPED_ALB_NAME_PREFIX + IntStream.range(0, MAX_ALBS_PER_REGION).filter(i->!numbersTaken.contains(i)).min().getAsInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateDNSBasedLoadBalancerMapping<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> build() throws JSchException, IOException, InterruptedException, SftpException {
|
||||
return new CreateDNSBasedLoadBalancerMapping<>(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static <ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> builder() {
|
||||
return new BuilderImpl<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks a new load balancer name following the pattern {@link #DNS_MAPPED_ALB_NAME_PREFIX}{@code [0-9]+} that is not
|
||||
* part of {@code loadBalancerNames} and has the least number.
|
||||
*/
|
||||
private static String getAvailableDNSMappedAlbName(Set<String> loadBalancerNames) {
|
||||
final Set<Integer> numbersTaken = new HashSet<>();
|
||||
for (final String loadBalancerName : loadBalancerNames) {
|
||||
final Matcher matcher = ALB_NAME_PATTERN.matcher(loadBalancerName);
|
||||
if (matcher.find()) {
|
||||
numbersTaken.add(Integer.parseInt(matcher.group(1)));
|
||||
}
|
||||
}
|
||||
return DNS_MAPPED_ALB_NAME_PREFIX + IntStream.range(0, MAX_ALBS_PER_REGION).filter(i->!numbersTaken.contains(i)).min().getAsInt();
|
||||
protected CreateDNSBasedLoadBalancerMapping(BuilderImpl<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> builder) throws JSchException, IOException, InterruptedException, SftpException {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+56
-35
@@ -1,11 +1,9 @@
|
||||
package com.sap.sse.landscape.aws.orchestration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.SftpException;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.landscape.Region;
|
||||
import com.sap.sse.landscape.application.ApplicationMasterProcess;
|
||||
import com.sap.sse.landscape.application.ApplicationProcess;
|
||||
@@ -24,43 +22,66 @@ import com.sap.sse.landscape.orchestration.Procedure;
|
||||
public class CreateDynamicLoadBalancerMapping<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
extends CreateLoadBalancerMapping<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, AwsInstance<ShardingKey, MetricsT>>
|
||||
implements Procedure<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
|
||||
public CreateDynamicLoadBalancerMapping(
|
||||
ApplicationProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> process, String hostname,
|
||||
String targetGroupNamePrefix,
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape,
|
||||
Optional<Duration> optionalTimeout) throws JSchException, IOException, InterruptedException, SftpException {
|
||||
super(process, getOrCreateNonDNSMappedLoadBalancer(process.getHost().getRegion(), hostname, landscape), hostname,
|
||||
targetGroupNamePrefix, landscape, optionalTimeout);
|
||||
}
|
||||
|
||||
protected static <ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
extends CreateLoadBalancerMapping<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT>
|
||||
implements Procedure<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
|
||||
public static interface Builder<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>>
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> getOrCreateNonDNSMappedLoadBalancer(
|
||||
Region region, String hostname,
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape) {
|
||||
final String domainName = getHostedZoneName(hostname);
|
||||
final ApplicationLoadBalancer<ShardingKey, MetricsT> existingLoadBalancer = landscape.getNonDNSMappedLoadBalancer(region, domainName);
|
||||
final ApplicationLoadBalancer<ShardingKey, MetricsT> result;
|
||||
if (existingLoadBalancer != null) {
|
||||
result = existingLoadBalancer;
|
||||
} else {
|
||||
result = landscape.createNonDNSMappedLoadBalancer(region, domainName);
|
||||
createWildcardRoute53Mapping(landscape, result, domainName);
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
extends CreateLoadBalancerMapping.Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> {
|
||||
CreateDynamicLoadBalancerMapping<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> build() throws JSchException, IOException, InterruptedException, SftpException;
|
||||
}
|
||||
|
||||
protected static class BuilderImpl<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
extends CreateLoadBalancerMapping.BuilderImpl<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT>
|
||||
implements Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> {
|
||||
@Override
|
||||
public ApplicationLoadBalancer<ShardingKey, MetricsT> getLoadBalancerUsed() throws InterruptedException {
|
||||
final ApplicationLoadBalancer<ShardingKey, MetricsT> result;
|
||||
if (super.getLoadBalancerUsed() != null) {
|
||||
result = super.getLoadBalancerUsed();
|
||||
} else {
|
||||
result = getOrCreateNonDNSMappedLoadBalancer(getProcess().getHost().getRegion(), getHostname(), getLandscape());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected ApplicationLoadBalancer<ShardingKey, MetricsT> getOrCreateNonDNSMappedLoadBalancer(
|
||||
Region region, String hostname, AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape) {
|
||||
final String domainName = getHostedZoneName(hostname);
|
||||
final ApplicationLoadBalancer<ShardingKey, MetricsT> existingLoadBalancer = landscape.getNonDNSMappedLoadBalancer(region, domainName);
|
||||
final ApplicationLoadBalancer<ShardingKey, MetricsT> result;
|
||||
if (existingLoadBalancer != null) {
|
||||
result = existingLoadBalancer;
|
||||
} else {
|
||||
result = landscape.createNonDNSMappedLoadBalancer(region, domainName);
|
||||
createWildcardRoute53Mapping(landscape, result, domainName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void createWildcardRoute53Mapping(
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape,
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancer, String domainName) {
|
||||
final String hostname = "*." + domainName;
|
||||
landscape.setDNSRecordToApplicationLoadBalancer(landscape.getDNSHostedZoneId(domainName), hostname, loadBalancer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateDynamicLoadBalancerMapping<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> build() throws JSchException, IOException, InterruptedException, SftpException {
|
||||
return new CreateDynamicLoadBalancerMapping<>(this);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static <ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
public static <ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>>
|
||||
void createWildcardRoute53Mapping(
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape,
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancer,
|
||||
String domainName) {
|
||||
final String hostname = "*." + domainName;
|
||||
landscape.setDNSRecordToApplicationLoadBalancer(landscape.getDNSHostedZoneId(domainName), hostname, loadBalancer);
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> builder() {
|
||||
return new BuilderImpl<>();
|
||||
}
|
||||
|
||||
protected CreateDynamicLoadBalancerMapping(BuilderImpl<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> builder) throws JSchException, IOException, InterruptedException, SftpException {
|
||||
super(builder);
|
||||
}
|
||||
}
|
||||
|
||||
+74
-8
@@ -81,15 +81,81 @@ extends ProcedureWithTargetGroup<ShardingKey, MetricsT, MasterProcessT, ReplicaP
|
||||
private TargetGroup<ShardingKey, MetricsT> masterTargetGroupCreated;
|
||||
private TargetGroup<ShardingKey, MetricsT> publicTargetGroupCreated;
|
||||
private Iterable<Rule> rulesAdded;
|
||||
|
||||
/**
|
||||
* Default rules implemented by this builder:
|
||||
* <ul>
|
||||
* <li>The timeout for looking up the process's server name defaults to no timeout.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*/
|
||||
public static interface Builder<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
extends ProcedureWithTargetGroup.Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> {
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setProcess(ApplicationProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> process);
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setHostname(String hostname);
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setTimeout(Duration timeout);
|
||||
}
|
||||
|
||||
protected static class BuilderImpl<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
extends ProcedureWithTargetGroup.BuilderImpl<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT>
|
||||
implements Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> {
|
||||
private String hostname;
|
||||
private ApplicationProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> process;
|
||||
private Optional<Duration> optionalTimeout = Optional.empty();
|
||||
|
||||
public CreateLoadBalancerMapping(ApplicationProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> process,
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancerUsed, String hostname,
|
||||
String targetGroupNamePrefix,
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape,
|
||||
Optional<Duration> optionalTimeout) throws JSchException, IOException, InterruptedException, SftpException {
|
||||
super(loadBalancerUsed, targetGroupNamePrefix, landscape, process.getServerName(optionalTimeout));
|
||||
this.process = process;
|
||||
this.hostname = hostname;
|
||||
@Override
|
||||
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setProcess(
|
||||
ApplicationProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> process) {
|
||||
this.process = process;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public ApplicationProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> getProcess() {
|
||||
return process;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setTimeout(Duration timeout) {
|
||||
this.optionalTimeout = Optional.of(timeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Optional<Duration> getOptionalTimeout() {
|
||||
return optionalTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() throws JSchException, IOException, InterruptedException, SftpException {
|
||||
final String result;
|
||||
if (super.getServerName() != null) {
|
||||
result = super.getServerName();
|
||||
} else {
|
||||
result = getProcess().getServerName(getOptionalTimeout());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
protected CreateLoadBalancerMapping(BuilderImpl<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> builder) throws JSchException, IOException, InterruptedException, SftpException {
|
||||
super(builder);
|
||||
this.process = builder.getProcess();
|
||||
this.hostname = builder.getHostname();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+69
-8
@@ -31,15 +31,76 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
|
||||
private static final String MASTER_TARGET_GROUP_SUFFIX = "-m";
|
||||
private final ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancerUsed;
|
||||
private final String targetGroupNamePrefix;
|
||||
private final String servername;
|
||||
private final String serverName;
|
||||
private Iterable<Rule> rulesAdded;
|
||||
|
||||
public static interface Builder<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>> {
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setLoadBalancerUsed(ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancerUsed);
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setTargetGroupNamePrefix(String targetGroupNamePrefix);
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setServerName(String serverName);
|
||||
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setLandscape(AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape);
|
||||
}
|
||||
|
||||
protected static class BuilderImpl<ShardingKey, MetricsT extends ApplicationProcessMetrics,
|
||||
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
|
||||
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, HostT extends AwsInstance<ShardingKey, MetricsT>>
|
||||
implements Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> {
|
||||
private ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancerUsed;
|
||||
private String targetGroupNamePrefix;
|
||||
private String serverName;
|
||||
private AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape;
|
||||
|
||||
@Override
|
||||
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setLoadBalancerUsed(
|
||||
ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancerUsed) {
|
||||
this.loadBalancerUsed = loadBalancerUsed;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProcedureWithTargetGroup(ApplicationLoadBalancer<ShardingKey, MetricsT> loadBalancerUsed, String targetGroupNamePrefix,
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape, String servername) throws JSchException, IOException, InterruptedException, SftpException {
|
||||
super(landscape);
|
||||
this.loadBalancerUsed = loadBalancerUsed;
|
||||
this.targetGroupNamePrefix = targetGroupNamePrefix;
|
||||
this.servername = servername;
|
||||
@Override
|
||||
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setTargetGroupNamePrefix(
|
||||
String targetGroupNamePrefix) {
|
||||
this.targetGroupNamePrefix = targetGroupNamePrefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setServerName(String serverName) {
|
||||
this.serverName = serverName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ApplicationLoadBalancer<ShardingKey, MetricsT> getLoadBalancerUsed() throws InterruptedException {
|
||||
return loadBalancerUsed;
|
||||
}
|
||||
|
||||
public String getTargetGroupNamePrefix() {
|
||||
return targetGroupNamePrefix;
|
||||
}
|
||||
|
||||
public String getServerName() throws JSchException, IOException, InterruptedException, SftpException {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> setLandscape(
|
||||
AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> landscape) {
|
||||
this.landscape = landscape;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AwsLandscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> getLandscape() {
|
||||
return landscape;
|
||||
}
|
||||
}
|
||||
|
||||
protected ProcedureWithTargetGroup(BuilderImpl<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> builder) throws JSchException, IOException, InterruptedException, SftpException {
|
||||
super(builder.getLandscape());
|
||||
this.loadBalancerUsed = builder.getLoadBalancerUsed();
|
||||
this.targetGroupNamePrefix = builder.getTargetGroupNamePrefix();
|
||||
this.serverName = builder.getServerName();
|
||||
}
|
||||
|
||||
protected TargetGroup<ShardingKey, MetricsT> createTargetGroup(Region region, String targetGroupName,
|
||||
@@ -63,7 +124,7 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
|
||||
}
|
||||
|
||||
protected String getPublicTargetGroupName() {
|
||||
return targetGroupNamePrefix+servername;
|
||||
return targetGroupNamePrefix+serverName;
|
||||
}
|
||||
|
||||
protected TargetGroup<ShardingKey, MetricsT> getPublicTargetGroup() throws JSchException, IOException, InterruptedException, SftpException {
|
||||
|
||||
Reference in New Issue
Block a user