bug5838: make creation of auto-scaling group and launch configuration aware of VPCs

This commit is contained in:
Axel Uhl
2023-04-26 15:10:34 +02:00
parent 26fef91b84
commit 9dadbfdc68
4 changed files with 27 additions and 19 deletions
@@ -1713,7 +1713,7 @@ public class LandscapeServiceImpl implements LandscapeService {
.setRegion(region)
.setPathPrefixForShardingKey(RemoteServiceMappingConstants.pathPrefixForShardingKey)
.setShardingKeys(shardingKeys)
.setReplicaset(applicationReplicaSet)
.setReplicaSet(applicationReplicaSet)
.setShardName(shardName)
.build()
.run();
@@ -1735,7 +1735,7 @@ public class LandscapeServiceImpl implements LandscapeService {
.setRegion(region)
.setPathPrefixForShardingKey(RemoteServiceMappingConstants.pathPrefixForShardingKey)
.setShardingKeys(shardingkeys)
.setReplicaset(applicationReplicaSet)
.setReplicaSet(applicationReplicaSet)
.setShardName(shardName)
.build()
.run();
@@ -1768,7 +1768,7 @@ public class LandscapeServiceImpl implements LandscapeService {
.setLandscape(getLandscape())
.setTargetGroupNamePrefix(LandscapeService.SAILING_TARGET_GROUP_NAME_PREFIX)
.setShardingKeys(shardingkeys)
.setReplicaset(applicationReplicaSet)
.setReplicaSet(applicationReplicaSet)
.setRegion(region)
.setPathPrefixForShardingKey(RemoteServiceMappingConstants.pathPrefixForShardingKey)
.setShardName(shardName)
@@ -341,6 +341,12 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey>
return result;
}
private Subnet getSubnetForAvailabilityZoneInSameVpcAsSecurityGroup(AwsAvailabilityZone az, SecurityGroup securityGroup, Region region) {
final Ec2Client ec2Client = getEc2Client(region);
final String vpcId = ec2Client.describeSecurityGroups(b->b.groupIds(securityGroup.getId())).securityGroups().iterator().next().vpcId();
return ec2Client.describeSubnets(b->b.filters(Filter.builder().name("vpc-id").values(vpcId).build())).subnets().iterator().next();
}
private <MetricsT extends ApplicationProcessMetrics, ProcessT extends ApplicationProcess<ShardingKey, MetricsT, ProcessT>>
Listener createLoadBalancerHttpListener(ApplicationLoadBalancer<ShardingKey> alb) {
return getLoadBalancingClient(getRegion(alb.getRegion()))
@@ -504,6 +510,11 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey>
/**
* Grabs all subnets that are default subnet for any of the availability zones specified
* <p>
*
* FIXME bug5838: for a non-default VPC its subnets won't be the default subnets for their AZs either. Hence, we
* need to get the VPC-ID, either immediately or through a security group whose
* {@link software.amazon.awssdk.services.ec2.model.SecurityGroup#vpcId() VPC-ID} could be used
*/
private Iterable<Subnet> getSubnetsForAvailabilityZones(Region region, Iterable<AwsAvailabilityZone> azs) {
return Util.filter(getEc2Client(region).describeSubnets().subnets(), subnet -> subnet.defaultForAz()
@@ -934,14 +945,8 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey>
.instanceType(instanceType).keyName(keyName)
.placement(Placement.builder().availabilityZone(az.getName()).build())
.securityGroupIds(Util.mapToArrayList(securityGroups, SecurityGroup::getId));
final List<software.amazon.awssdk.services.ec2.model.SecurityGroup> awsSecurityGroups = ec2Client.describeSecurityGroups(
b->b.groupIds(Util.asList(Util.map(securityGroups, SecurityGroup::getId)))).securityGroups();
ec2Client.describeSubnets().subnets().stream().filter(
subnet->
subnet.availabilityZoneId().equals(az.getId()) &&
subnet.vpcId().equals(awsSecurityGroups.iterator().next().vpcId()))
.findFirst()
.map(subnet->runInstancesRequestBuilder.subnetId(subnet.subnetId()));
runInstancesRequestBuilder.subnetId(getSubnetForAvailabilityZoneInSameVpcAsSecurityGroup(
az, securityGroups.iterator().next(), getRegion(az.getRegion())).subnetId());
if (userData != null) {
runInstancesRequestBuilder.userData(Base64.getEncoder().encodeToString(String.join("\n", userData).getBytes()));
}
@@ -1941,18 +1946,20 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey>
String imageId, AwsApplicationConfiguration<ShardingKey, MetricsT, ProcessT> replicaConfiguration,
int minReplicas, int maxReplicas, int maxRequestsPerTarget) {
logger.info("Creating launch configuration for replica set "+replicaSetName);
final AutoScalingClient autoScalingClient = getAutoScalingClient(getRegion(region));
final Region awsRegion = getRegion(region);
final AutoScalingClient autoScalingClient = getAutoScalingClient(awsRegion);
final String releaseName = replicaConfiguration.getRelease().map(r->r.getName()).orElse("UnknownRelease");
final String launchConfigurationName = getLaunchConfigurationName(replicaSetName, releaseName);
final String autoScalingGroupName = getAutoScalingGroupName(replicaSetName);
final Iterable<AwsAvailabilityZone> availabilityZones = getAvailabilityZones(region);
final SecurityGroup securityGroup = getDefaultSecurityGroupForApplicationHosts(region);
final int instanceWarmupTimeInSeconds = (int) Duration.ONE_MINUTE.times(3).asSeconds();
autoScalingClient.createLaunchConfiguration(b->b
.launchConfigurationName(launchConfigurationName)
.keyName(keyName)
.imageId(imageId)
.instanceMonitoring(i->i.enabled(true))
.securityGroups(getDefaultSecurityGroupForApplicationHosts(region).getId())
.securityGroups(securityGroup.getId())
.userData(Base64.getEncoder().encodeToString(replicaConfiguration.getAsEnvironmentVariableAssignments().getBytes()))
.instanceType(instanceType.toString()));
logger.info("Creating auto-scaling group for replica set "+replicaSetName);
@@ -1962,7 +1969,8 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey>
.maxSize(maxReplicas)
.healthCheckGracePeriod(instanceWarmupTimeInSeconds)
.autoScalingGroupName(autoScalingGroupName)
.availabilityZones(Util.toArray(Util.map(availabilityZones, az->az.getName()), new String[3]))
.vpcZoneIdentifier(Util.joinStrings(",", Util.map(availabilityZones,
az->getSubnetForAvailabilityZoneInSameVpcAsSecurityGroup(az, securityGroup, awsRegion))))
.targetGroupARNs(publicTargetGroup.getTargetGroupArn())
.launchConfigurationName(launchConfigurationName);
tags.ifPresent(t->{
@@ -54,8 +54,8 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
protected final ShardingKey SHARDING_KEY_UNUSED_BY_ANY_APPLICATION = (ShardingKey) "lauycaluy3cla3yrclaurlIYQL8";
protected final String shardName;
final protected Set<ShardingKey> shardingKeys;
final AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> replicaSet;
final Region region;
final protected AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> replicaSet;
final protected Region region;
private final String pathPrefixForShardingKey;
protected ShardProcedure(BuilderImpl<?,?, ShardingKey, MetricsT, ProcessT> builder) throws Exception {
@@ -82,7 +82,7 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
BuilderT setShardingKeys(Set<ShardingKey> shardingkeys);
BuilderT setReplicaset(AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> replicaset);
BuilderT setReplicaSet(AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> replicaset);
BuilderT setRegion(Region region);
}
@@ -122,7 +122,7 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
}
@Override
public BuilderT setReplicaset(AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> replicaset) {
public BuilderT setReplicaSet(AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> replicaset) {
this.replicaSet = replicaset;
return self();
}