diff --git a/java/com.sap.sse.landscape.aws.test/src/com/sap/sse/landscape/aws/ConnectivityTest.java b/java/com.sap.sse.landscape.aws.test/src/com/sap/sse/landscape/aws/ConnectivityTest.java index c8d2afe9f8d..a14daf18529 100755 --- a/java/com.sap.sse.landscape.aws.test/src/com/sap/sse/landscape/aws/ConnectivityTest.java +++ b/java/com.sap.sse.landscape.aws.test/src/com/sap/sse/landscape/aws/ConnectivityTest.java @@ -29,7 +29,6 @@ import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.landscape.application.ApplicationProcessMetrics; import com.sap.sse.landscape.aws.impl.AmazonMachineImage; -import com.sap.sse.landscape.aws.impl.AwsAvailabilityZoneImpl; import com.sap.sse.landscape.aws.impl.AwsRegion; import com.sap.sse.landscape.ssh.SSHKeyPair; @@ -63,7 +62,7 @@ public class ConnectivityTest { @Test public void testConnectivity() { final AwsInstance host = landscape.launchHost(landscape.getImage(region, "ami-01b4b27a5699e33e6"), - new AwsAvailabilityZoneImpl("eu-west-2b", region), "Axel", Collections.singleton(()->"sg-0b2afd48960251280")); + landscape.getAvailabilityZoneByName(region, "eu-west-2b"), "Axel", Collections.singleton(()->"sg-0b2afd48960251280")); try { assertNotNull(host); } finally { @@ -133,7 +132,7 @@ public class ConnectivityTest { private void testSshConnectWithKey(final String keyName) throws InterruptedException, JSchException { final AwsInstance host = landscape.launchHost(landscape.getImage(region, "ami-01b4b27a5699e33e6"), - new AwsAvailabilityZoneImpl("eu-west-2b", region), keyName, Collections.singleton(()->"sg-0b2afd48960251280")); + landscape.getAvailabilityZoneByName(region, "eu-west-2b"), keyName, Collections.singleton(()->"sg-0b2afd48960251280")); try { assertNotNull(host); logger.info("Created instance with ID "+host.getInstanceId()); @@ -213,7 +212,11 @@ public class ConnectivityTest { public void createEmptyLoadBalancerTest() { final String albName = "MyAlb"+new Random().nextInt(); final ApplicationLoadBalancer alb = landscape.createLoadBalancer(albName, region); - assertNotNull(alb); - assertEquals(albName, alb.getName()); + try { + assertNotNull(alb); + assertEquals(albName, alb.getName()); + } finally { + landscape.deleteLoadBalancer(alb); + } } } diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/ApplicationLoadBalancer.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/ApplicationLoadBalancer.java index 13a78c0ba3d..a2724e9bb02 100755 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/ApplicationLoadBalancer.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/ApplicationLoadBalancer.java @@ -1,6 +1,7 @@ package com.sap.sse.landscape.aws; import com.sap.sse.common.Named; +import com.sap.sse.landscape.Region; /** * Represents an AWS Application Load Balancer (ALB). When created, a default configuration with the following @@ -25,4 +26,8 @@ public interface ApplicationLoadBalancer extends Named { void addRules(Iterable rulesToAdd); void deleteRules(Iterable rulesToDelete); + + Region getRegion(); + + String getArn(); } diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsAvailabilityZone.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsAvailabilityZone.java index 2fa91f40d00..8259619dd67 100644 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsAvailabilityZone.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsAvailabilityZone.java @@ -1,7 +1,9 @@ package com.sap.sse.landscape.aws; import com.sap.sse.landscape.AvailabilityZone; +import com.sap.sse.landscape.aws.impl.AwsRegion; public interface AwsAvailabilityZone extends AvailabilityZone { - + @Override + AwsRegion getRegion(); } diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsLandscape.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsLandscape.java index b9463dfefe7..f6fc4fa6a43 100755 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsLandscape.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsLandscape.java @@ -10,6 +10,7 @@ import com.sap.sse.landscape.SecurityGroup; import com.sap.sse.landscape.application.ApplicationProcessMetrics; import com.sap.sse.landscape.aws.impl.AmazonMachineImage; import com.sap.sse.landscape.aws.impl.AwsLandscapeImpl; +import com.sap.sse.landscape.aws.impl.AwsRegion; import com.sap.sse.landscape.ssh.SSHKeyPair; import software.amazon.awssdk.services.cloudwatch.CloudWatchClient; @@ -54,7 +55,7 @@ public interface AwsLandscape fromImage, AvailabilityZone az, String keyName, Iterable securityGroups) { + default AwsInstance launchHost(MachineImage fromImage, AwsAvailabilityZone az, String keyName, Iterable securityGroups) { return launchHosts(1, fromImage, az, keyName, securityGroups).iterator().next(); } @@ -66,7 +67,7 @@ public interface AwsLandscape launchHosts(int numberOfHostsToLaunch, MachineImage fromImage, AvailabilityZone az, + Iterable launchHosts(int numberOfHostsToLaunch, MachineImage fromImage, AwsAvailabilityZone az, String keyName, Iterable securityGroups); AmazonMachineImage getImage(Region region, String imageId); @@ -143,4 +144,8 @@ public interface AwsLandscape getAvailabilityZones(Region awsRegion); + + AwsAvailabilityZone getAvailabilityZoneByName(AwsRegion region, String availabilityZoneName); + + void deleteLoadBalancer(ApplicationLoadBalancer alb); } diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApplicationLoadBalancerImpl.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApplicationLoadBalancerImpl.java index 2ea7a2ab137..d37ccdd2850 100644 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApplicationLoadBalancerImpl.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApplicationLoadBalancerImpl.java @@ -9,8 +9,11 @@ public class ApplicationLoadBalancerImpl implements ApplicationLoadBalancer { private static final long serialVersionUID = -5297220031399131769L; final LoadBalancer loadBalancer; + + private final com.sap.sse.landscape.Region region; - public ApplicationLoadBalancerImpl(LoadBalancer loadBalancer) { + public ApplicationLoadBalancerImpl(com.sap.sse.landscape.Region region, LoadBalancer loadBalancer) { + this.region = region; this.loadBalancer = loadBalancer; } @@ -24,6 +27,16 @@ public class ApplicationLoadBalancerImpl implements ApplicationLoadBalancer { return loadBalancer.dnsName(); } + @Override + public String getArn() { + return loadBalancer.loadBalancerArn(); + } + + @Override + public com.sap.sse.landscape.Region getRegion() { + return region; + } + @Override public Iterable getRules() { // TODO Auto-generated method stub diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsAvailabilityZoneImpl.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsAvailabilityZoneImpl.java index 47ac197bc7f..29cd06b245b 100755 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsAvailabilityZoneImpl.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsAvailabilityZoneImpl.java @@ -1,20 +1,21 @@ package com.sap.sse.landscape.aws.impl; -import com.sap.sse.landscape.Region; +import com.sap.sse.common.impl.NamedImpl; import com.sap.sse.landscape.aws.AwsAvailabilityZone; -public class AwsAvailabilityZoneImpl implements AwsAvailabilityZone { +public class AwsAvailabilityZoneImpl extends NamedImpl implements AwsAvailabilityZone { + private static final long serialVersionUID = 7081008193504850891L; private final String id; - private final Region region; + private final AwsRegion region; - public AwsAvailabilityZoneImpl(String id, Region region) { - super(); + public AwsAvailabilityZoneImpl(String id, String name, AwsRegion region) { + super(name); this.id = id; this.region = region; } public AwsAvailabilityZoneImpl(software.amazon.awssdk.services.ec2.model.AvailabilityZone az) { - this(az.zoneName(), new AwsRegion(az.regionName())); + this(az.zoneId(), az.zoneName(), new AwsRegion(az.regionName())); } @Override @@ -23,7 +24,7 @@ public class AwsAvailabilityZoneImpl implements AwsAvailabilityZone { } @Override - public Region getRegion() { + public AwsRegion getRegion() { return region; } diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsInstanceImpl.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsInstanceImpl.java index d0431f06309..5c4ff2a9e36 100755 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsInstanceImpl.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsInstanceImpl.java @@ -16,8 +16,8 @@ import com.sap.sse.landscape.AvailabilityZone; import com.sap.sse.landscape.Log; import com.sap.sse.landscape.Metrics; import com.sap.sse.landscape.Process; -import com.sap.sse.landscape.Region; import com.sap.sse.landscape.SecurityGroup; +import com.sap.sse.landscape.aws.AwsAvailabilityZone; import com.sap.sse.landscape.aws.AwsInstance; import com.sap.sse.landscape.aws.AwsLandscape; import com.sap.sse.landscape.ssh.JCraftLogAdapter; @@ -28,10 +28,10 @@ import software.amazon.awssdk.services.ec2.model.Instance; public class AwsInstanceImpl implements AwsInstance { private final String instanceId; - private final AvailabilityZone availabilityZone; + private final AwsAvailabilityZone availabilityZone; private final AwsLandscape landscape; - public AwsInstanceImpl(String instanceId, AvailabilityZone availabilityZone, AwsLandscape landscape) { + public AwsInstanceImpl(String instanceId, AwsAvailabilityZone availabilityZone, AwsLandscape landscape) { this.instanceId = instanceId; this.availabilityZone = availabilityZone; this.landscape = landscape; @@ -149,10 +149,10 @@ public class AwsInstanceImpl implements AwsInstance { @Override public AvailabilityZone getAvailabilityZone() { - return new AwsAvailabilityZoneImpl(getInstance().placement().availabilityZone(), getRegion()); + return availabilityZone; } - private Region getRegion() { + private AwsRegion getRegion() { return availabilityZone.getRegion(); } diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java index 44defa28406..4bd51acb3b2 100755 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java @@ -21,6 +21,7 @@ import com.sap.sse.landscape.application.ApplicationProcessMetrics; import com.sap.sse.landscape.application.ApplicationReplicaSet; import com.sap.sse.landscape.application.Scope; import com.sap.sse.landscape.aws.ApplicationLoadBalancer; +import com.sap.sse.landscape.aws.AwsAvailabilityZone; import com.sap.sse.landscape.aws.AwsInstance; import com.sap.sse.landscape.aws.AwsLandscape; import com.sap.sse.landscape.aws.persistence.DomainObjectFactory; @@ -40,12 +41,10 @@ import software.amazon.awssdk.services.ec2.model.CreateKeyPairRequest; import software.amazon.awssdk.services.ec2.model.CreateKeyPairResponse; import software.amazon.awssdk.services.ec2.model.DeleteKeyPairRequest; import software.amazon.awssdk.services.ec2.model.DescribeAvailabilityZonesRequest; -import software.amazon.awssdk.services.ec2.model.DescribeAvailabilityZonesResponse; import software.amazon.awssdk.services.ec2.model.DescribeImagesRequest; import software.amazon.awssdk.services.ec2.model.DescribeImagesResponse; import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; import software.amazon.awssdk.services.ec2.model.DescribeKeyPairsRequest; -import software.amazon.awssdk.services.ec2.model.Filter; import software.amazon.awssdk.services.ec2.model.ImportKeyPairRequest; import software.amazon.awssdk.services.ec2.model.Instance; import software.amazon.awssdk.services.ec2.model.InstanceType; @@ -53,10 +52,12 @@ import software.amazon.awssdk.services.ec2.model.KeyPairInfo; import software.amazon.awssdk.services.ec2.model.Placement; import software.amazon.awssdk.services.ec2.model.RunInstancesRequest; import software.amazon.awssdk.services.ec2.model.RunInstancesResponse; +import software.amazon.awssdk.services.ec2.model.Subnet; import software.amazon.awssdk.services.ec2.model.TerminateInstancesRequest; import software.amazon.awssdk.services.elasticloadbalancingv2.ElasticLoadBalancingV2Client; import software.amazon.awssdk.services.elasticloadbalancingv2.model.CreateLoadBalancerRequest; import software.amazon.awssdk.services.elasticloadbalancingv2.model.CreateLoadBalancerResponse; +import software.amazon.awssdk.services.elasticloadbalancingv2.model.DeleteLoadBalancerRequest; import software.amazon.awssdk.services.elasticloadbalancingv2.model.DescribeLoadBalancersRequest; import software.amazon.awssdk.services.elasticloadbalancingv2.model.LoadBalancer; import software.amazon.awssdk.services.elasticloadbalancingv2.model.SubnetMapping; @@ -156,11 +157,34 @@ public class AwsLandscapeImpl availabilityZones = getAvailabilityZones(region); + final SubnetMapping[] subnetMappings = Util.toArray(Util.map(getSubnetsForAvailabilityZones(awsRegion, availabilityZones), + subnet->SubnetMapping.builder().subnetId(subnet.subnetId()).build()), new SubnetMapping[0]); final CreateLoadBalancerResponse response = client .createLoadBalancer(CreateLoadBalancerRequest.builder().name(name) - .subnetMappings(SubnetMapping.builder().subnetMappings) - .build()); - return new ApplicationLoadBalancerImpl(response.loadBalancers().iterator().next()); + .subnetMappings(subnetMappings).build()); + return new ApplicationLoadBalancerImpl(region, response.loadBalancers().iterator().next()); + } + + @Override + public void deleteLoadBalancer(ApplicationLoadBalancer alb) { + getLoadBalancingClient(getRegion(alb.getRegion())).deleteLoadBalancer(DeleteLoadBalancerRequest.builder().loadBalancerArn(alb.getArn()).build()); + } + + /** + * Grabs all subnets that are default subnet for any of the availability zones specified + */ + private Iterable getSubnetsForAvailabilityZones(Region region, Iterable azs) { + return Util.filter(getEc2Client(region).describeSubnets().subnets(), subnet -> subnet.defaultForAz() + && Util.contains(Util.map(azs, az -> az.getId()), subnet.availabilityZoneId())); + } + + @Override + public AwsAvailabilityZone getAvailabilityZoneByName(AwsRegion region, String availabilityZoneName) { + final software.amazon.awssdk.services.ec2.model.AvailabilityZone awsAz = getEc2Client(getRegion(region)) + .describeAvailabilityZones( + DescribeAvailabilityZonesRequest.builder().zoneNames(availabilityZoneName).build()) + .availabilityZones().iterator().next(); + return new AwsAvailabilityZoneImpl(awsAz); } @Override @@ -168,7 +192,7 @@ public class AwsLandscapeImpl launchHosts(int numberOfHostsToLaunch, MachineImage fromImage, AvailabilityZone az, + public Iterable launchHosts(int numberOfHostsToLaunch, MachineImage fromImage, AwsAvailabilityZone az, String keyName, Iterable securityGroups) { if (!fromImage.getRegion().equals(az.getRegion())) { throw new IllegalArgumentException("Trying to launch an instance in region "+az.getRegion()+ @@ -335,12 +359,7 @@ public class AwsLandscapeImpl getAvailabilityZones(com.sap.sse.landscape.Region awsRegion) { - final DescribeAvailabilityZonesResponse zones = getEc2Client(getRegion(awsRegion)).describeAvailabilityZones( - DescribeAvailabilityZonesRequest.builder().filters(Filter.builder().name(name))build()); - final List azs = zones.availabilityZones(); - for (final software.amazon.awssdk.services.ec2.model.AvailabilityZone az : azs) { - az. - } - return Util.map(zones.availabilityZones(), AwsAvailabilityZoneImpl::new); + return Util.map(getEc2Client(getRegion(awsRegion)).describeAvailabilityZones().availabilityZones(), + AwsAvailabilityZoneImpl::new); } } diff --git a/java/com.sap.sse.landscape/src/com/sap/sse/landscape/AvailabilityZone.java b/java/com.sap.sse.landscape/src/com/sap/sse/landscape/AvailabilityZone.java index 495798bbf0b..b57921bdc93 100755 --- a/java/com.sap.sse.landscape/src/com/sap/sse/landscape/AvailabilityZone.java +++ b/java/com.sap.sse.landscape/src/com/sap/sse/landscape/AvailabilityZone.java @@ -1,8 +1,9 @@ package com.sap.sse.landscape; +import com.sap.sse.common.Named; import com.sap.sse.common.WithID; -public interface AvailabilityZone extends WithID { +public interface AvailabilityZone extends Named, WithID { @Override String getId();