b492da23f4d3a3775cc30ececcbdd972b150f02c
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/server/LandscapeManagementWriteServiceImpl.java
| ... | ... | @@ -81,6 +81,7 @@ import com.sap.sse.landscape.aws.impl.AwsApplicationReplicaSetImpl; |
| 81 | 81 | import com.sap.sse.landscape.aws.impl.AwsAvailabilityZoneImpl; |
| 82 | 82 | import com.sap.sse.landscape.aws.impl.AwsInstanceImpl; |
| 83 | 83 | import com.sap.sse.landscape.aws.impl.AwsRegion; |
| 84 | +import com.sap.sse.landscape.aws.impl.DNSCache; |
|
| 84 | 85 | import com.sap.sse.landscape.aws.orchestration.CreateDNSBasedLoadBalancerMapping; |
| 85 | 86 | import com.sap.sse.landscape.aws.orchestration.CreateDynamicLoadBalancerMapping; |
| 86 | 87 | import com.sap.sse.landscape.aws.orchestration.CreateLoadBalancerMapping; |
| ... | ... | @@ -562,9 +563,10 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem |
| 562 | 563 | final CompletableFuture<Iterable<ApplicationLoadBalancer<String>>> allLoadBalancersInRegion = landscape.getLoadBalancersAsync(region); |
| 563 | 564 | final CompletableFuture<Map<TargetGroup<String>, Iterable<TargetHealthDescription>>> allTargetGroupsInRegion = landscape.getTargetGroupsAsync(region); |
| 564 | 565 | final CompletableFuture<Map<Listener, Iterable<Rule>>> allLoadBalancerRulesInRegion = landscape.getLoadBalancerListenerRulesAsync(region, allLoadBalancersInRegion); |
| 566 | + final DNSCache dnsCache = landscape.getNewDNSCache(); |
|
| 565 | 567 | final ApplicationReplicaSet<String,SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> applicationReplicaSet = |
| 566 | 568 | new AwsApplicationReplicaSetImpl<>(name, masterHostname, master, /* no replicas yet */ Optional.empty(), |
| 567 | - allLoadBalancersInRegion, allTargetGroupsInRegion, allLoadBalancerRulesInRegion); |
|
| 569 | + allLoadBalancersInRegion, allTargetGroupsInRegion, allLoadBalancerRulesInRegion, landscape, dnsCache); |
|
| 568 | 570 | final CreateLaunchConfigurationAndAutoScalingGroup.Builder<String, ?, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> createLaunchConfigurationAndAutoScalingGroupBuilder = |
| 569 | 571 | CreateLaunchConfigurationAndAutoScalingGroup.builder(landscape, region, applicationReplicaSet, userBearerToken, createLoadBalancerMapping.getPublicTargetGroup()); |
| 570 | 572 | createLaunchConfigurationAndAutoScalingGroupBuilder |
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsLandscape.java
| ... | ... | @@ -23,6 +23,7 @@ import com.sap.sse.landscape.aws.impl.AwsInstanceImpl; |
| 23 | 23 | import com.sap.sse.landscape.aws.impl.AwsLandscapeImpl; |
| 24 | 24 | import com.sap.sse.landscape.aws.impl.AwsRegion; |
| 25 | 25 | import com.sap.sse.landscape.aws.impl.AwsTargetGroupImpl; |
| 26 | +import com.sap.sse.landscape.aws.impl.DNSCache; |
|
| 26 | 27 | import com.sap.sse.landscape.aws.orchestration.AwsApplicationConfiguration; |
| 27 | 28 | import com.sap.sse.landscape.mongodb.Database; |
| 28 | 29 | import com.sap.sse.landscape.mongodb.MongoEndpoint; |
| ... | ... | @@ -51,6 +52,7 @@ import software.amazon.awssdk.services.elasticloadbalancingv2.model.TargetHealth |
| 51 | 52 | import software.amazon.awssdk.services.route53.Route53Client; |
| 52 | 53 | import software.amazon.awssdk.services.route53.model.ChangeInfo; |
| 53 | 54 | import software.amazon.awssdk.services.route53.model.RRType; |
| 55 | +import software.amazon.awssdk.services.route53.model.ResourceRecordSet; |
|
| 54 | 56 | import software.amazon.awssdk.services.sts.model.Credentials; |
| 55 | 57 | |
| 56 | 58 | /** |
| ... | ... | @@ -620,4 +622,8 @@ public interface AwsLandscape<ShardingKey> extends Landscape<ShardingKey> { |
| 620 | 622 | static String getHostedZoneName(String hostname) { |
| 621 | 623 | return hostname.substring(hostname.indexOf('.')+1); |
| 622 | 624 | } |
| 625 | + |
|
| 626 | + CompletableFuture<Iterable<ResourceRecordSet>> getResourceRecordSetsAsync(String hostname); |
|
| 627 | + |
|
| 628 | + DNSCache getNewDNSCache(); |
|
| 623 | 629 | } |
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsApplicationReplicaSetImpl.java
| ... | ... | @@ -18,6 +18,7 @@ import com.sap.sse.landscape.application.impl.ApplicationReplicaSetImpl; |
| 18 | 18 | import com.sap.sse.landscape.aws.ApplicationLoadBalancer; |
| 19 | 19 | import com.sap.sse.landscape.aws.AwsApplicationReplicaSet; |
| 20 | 20 | import com.sap.sse.landscape.aws.AwsAutoScalingGroup; |
| 21 | +import com.sap.sse.landscape.aws.AwsLandscape; |
|
| 21 | 22 | import com.sap.sse.landscape.aws.TargetGroup; |
| 22 | 23 | |
| 23 | 24 | import software.amazon.awssdk.services.autoscaling.model.AutoScalingGroup; |
| ... | ... | @@ -28,6 +29,7 @@ import software.amazon.awssdk.services.elasticloadbalancingv2.model.ProtocolEnum |
| 28 | 29 | import software.amazon.awssdk.services.elasticloadbalancingv2.model.Rule; |
| 29 | 30 | import software.amazon.awssdk.services.elasticloadbalancingv2.model.TargetHealthDescription; |
| 30 | 31 | import software.amazon.awssdk.services.route53.Route53AsyncClient; |
| 32 | +import software.amazon.awssdk.services.route53.model.RRType; |
|
| 31 | 33 | import software.amazon.awssdk.services.route53.model.ResourceRecordSet; |
| 32 | 34 | |
| 33 | 35 | /** |
| ... | ... | @@ -57,12 +59,14 @@ implements AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> { |
| 57 | 59 | private final CompletableFuture<TargetGroup<ShardingKey>> masterTargetGroup; |
| 58 | 60 | private final CompletableFuture<TargetGroup<ShardingKey>> publicTargetGroup; |
| 59 | 61 | private final CompletableFuture<ResourceRecordSet> resourceRecordSet; |
| 62 | + private final AwsLandscape<ShardingKey> landscape; |
|
| 60 | 63 | |
| 61 | 64 | public AwsApplicationReplicaSetImpl(String replicaSetAndServerName, String hostname, ProcessT master, Optional<Iterable<ProcessT>> replicas, |
| 62 | 65 | CompletableFuture<Iterable<ApplicationLoadBalancer<ShardingKey>>> allLoadBalancersInRegion, |
| 63 | 66 | CompletableFuture<Map<TargetGroup<ShardingKey>, Iterable<TargetHealthDescription>>> allTargetGroupsInRegion, |
| 64 | - CompletableFuture<Map<Listener, Iterable<Rule>>> allLoadBalancerRulesInRegion) { |
|
| 67 | + CompletableFuture<Map<Listener, Iterable<Rule>>> allLoadBalancerRulesInRegion, AwsLandscape<ShardingKey> landscape, DNSCache dnsCache) { |
|
| 65 | 68 | super(replicaSetAndServerName, hostname, master, replicas); |
| 69 | + this.landscape = landscape; |
|
| 66 | 70 | autoScalingGroup = new CompletableFuture<>(); |
| 67 | 71 | defaultRedirectRule = new CompletableFuture<>(); |
| 68 | 72 | hostedZoneId = new CompletableFuture<>(); |
| ... | ... | @@ -73,7 +77,7 @@ implements AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> { |
| 73 | 77 | resourceRecordSet = new CompletableFuture<>(); |
| 74 | 78 | allLoadBalancersInRegion.thenCompose(loadBalancers-> |
| 75 | 79 | allTargetGroupsInRegion.thenCompose(targetGroupsAndTheirTargetHealthDescriptions-> |
| 76 | - allLoadBalancerRulesInRegion.handle((listenersAndTheirRules, e)->establishState(loadBalancers, targetGroupsAndTheirTargetHealthDescriptions, listenersAndTheirRules)))) |
|
| 80 | + allLoadBalancerRulesInRegion.handle((listenersAndTheirRules, e)->establishState(loadBalancers, targetGroupsAndTheirTargetHealthDescriptions, listenersAndTheirRules, dnsCache)))) |
|
| 77 | 81 | .handle((v, e)->{ |
| 78 | 82 | if (e != null) { |
| 79 | 83 | logger.log(Level.SEVERE, "Exception while trying to establish state of application replica set "+getName(), e); |
| ... | ... | @@ -82,11 +86,14 @@ implements AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> { |
| 82 | 86 | }); |
| 83 | 87 | } |
| 84 | 88 | |
| 85 | - public AwsApplicationReplicaSetImpl(String replicaSetAndServerName, ProcessT master, Optional<Iterable<ProcessT>> replicas, |
|
| 89 | + public AwsApplicationReplicaSetImpl(String replicaSetAndServerName, ProcessT master, |
|
| 90 | + Optional<Iterable<ProcessT>> replicas, |
|
| 86 | 91 | CompletableFuture<Iterable<ApplicationLoadBalancer<ShardingKey>>> allLoadBalancersInRegion, |
| 87 | 92 | CompletableFuture<Map<TargetGroup<ShardingKey>, Iterable<TargetHealthDescription>>> allTargetGroupsInRegion, |
| 88 | - CompletableFuture<Map<Listener, Iterable<Rule>>> allLoadBalancerRulesInRegion) { |
|
| 89 | - this(replicaSetAndServerName, /* hostname to be inferred */ null, master, replicas, allLoadBalancersInRegion, allTargetGroupsInRegion, allLoadBalancerRulesInRegion); |
|
| 93 | + CompletableFuture<Map<Listener, Iterable<Rule>>> allLoadBalancerRulesInRegion, |
|
| 94 | + AwsLandscape<ShardingKey> landscape, DNSCache dnsCache) { |
|
| 95 | + this(replicaSetAndServerName, /* hostname to be inferred */ null, master, replicas, allLoadBalancersInRegion, |
|
| 96 | + allTargetGroupsInRegion, allLoadBalancerRulesInRegion, landscape, dnsCache); |
|
| 90 | 97 | } |
| 91 | 98 | |
| 92 | 99 | /** |
| ... | ... | @@ -126,7 +133,7 @@ implements AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> { |
| 126 | 133 | */ |
| 127 | 134 | private Void establishState(Iterable<ApplicationLoadBalancer<ShardingKey>> loadBalancers, |
| 128 | 135 | Map<TargetGroup<ShardingKey>, Iterable<TargetHealthDescription>> targetGroupsAndTheirTargetHealthDescriptions, |
| 129 | - Map<Listener, Iterable<Rule>> listenersAndTheirRules) { |
|
| 136 | + Map<Listener, Iterable<Rule>> listenersAndTheirRules, DNSCache dnsCache) { |
|
| 130 | 137 | TargetGroup<ShardingKey> myMasterTargetGroup = null; |
| 131 | 138 | for (final Entry<TargetGroup<ShardingKey>, Iterable<TargetHealthDescription>> e : targetGroupsAndTheirTargetHealthDescriptions.entrySet()) { |
| 132 | 139 | if ((e.getKey().getProtocol() == ProtocolEnum.HTTP || e.getKey().getProtocol() == ProtocolEnum.HTTPS) |
| ... | ... | @@ -158,6 +165,25 @@ implements AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> { |
| 158 | 165 | // and we can determine the load balancer via the Listener now: |
| 159 | 166 | myLoadBalancer = Util.first(Util.filter(loadBalancers, loadBalancer->loadBalancer.getArn().equals(e.getKey().loadBalancerArn()))); |
| 160 | 167 | loadBalancer.complete(myLoadBalancer); |
| 168 | + dnsCache.getHostedZoneId(AwsLandscape.getHostedZoneName(hostname)).handle((hzid, ex)->hostedZoneId.complete(hzid)); |
|
| 169 | + dnsCache.getResourceRecordSetsAsync(hostname).thenAccept(resourceRecordSets-> |
|
| 170 | + Util.stream(resourceRecordSets).findFirst().ifPresent(rrs->{ |
|
| 171 | + resourceRecordSet.complete(rrs); |
|
| 172 | + try { |
|
| 173 | + if (rrs.type() == RRType.CNAME && !Util.isEmpty(Util.filter(rrs.resourceRecords(), rr->{ |
|
| 174 | + try { |
|
| 175 | + return rr.value().equals(getLoadBalancer().getDNSName()); |
|
| 176 | + } catch (InterruptedException | ExecutionException e1) { |
|
| 177 | + logger.log(Level.WARNING, "This shouldn't have happened", e1); |
|
| 178 | + throw new RuntimeException(e1); |
|
| 179 | + } |
|
| 180 | + }))) { |
|
| 181 | + logger.fine("Found DNS resource record "+getHostname()+" pointing to application replica set's load balancer "+getLoadBalancer().getArn()); |
|
| 182 | + } |
|
| 183 | + } catch (InterruptedException | ExecutionException e1) { |
|
| 184 | + logger.log(Level.WARNING, "This shouldn't have happened", e1); |
|
| 185 | + } |
|
| 186 | + })); |
|
| 161 | 187 | break outer; |
| 162 | 188 | } |
| 163 | 189 | } |
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java
| ... | ... | @@ -157,9 +157,6 @@ import software.amazon.awssdk.services.route53.model.ChangeInfo; |
| 157 | 157 | import software.amazon.awssdk.services.route53.model.ChangeResourceRecordSetsRequest; |
| 158 | 158 | import software.amazon.awssdk.services.route53.model.ChangeResourceRecordSetsResponse; |
| 159 | 159 | import software.amazon.awssdk.services.route53.model.GetChangeRequest; |
| 160 | -import software.amazon.awssdk.services.route53.model.HostedZone; |
|
| 161 | -import software.amazon.awssdk.services.route53.model.ListResourceRecordSetsRequest; |
|
| 162 | -import software.amazon.awssdk.services.route53.model.ListResourceRecordSetsResponse; |
|
| 163 | 160 | import software.amazon.awssdk.services.route53.model.RRType; |
| 164 | 161 | import software.amazon.awssdk.services.route53.model.ResourceRecord; |
| 165 | 162 | import software.amazon.awssdk.services.route53.model.ResourceRecordSet; |
| ... | ... | @@ -355,8 +352,7 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 355 | 352 | |
| 356 | 353 | @Override |
| 357 | 354 | public Iterable<TargetGroup<ShardingKey>> getTargetGroupsByLoadBalancerArn(com.sap.sse.landscape.Region region, String loadBalancerArn) { |
| 358 | - // FIXME handle "paging" in case nextMarker() is set in the response; see also describeTargetGroupsPaginator |
|
| 359 | - return Util.map(getLoadBalancingClient(getRegion(region)).describeTargetGroups(tg->tg.loadBalancerArn(loadBalancerArn)).targetGroups(), |
|
| 355 | + return Util.map(getLoadBalancingClient(getRegion(region)).describeTargetGroupsPaginator(tg->tg.loadBalancerArn(loadBalancerArn)).targetGroups(), |
|
| 360 | 356 | tg->new AwsTargetGroupImpl<>(this, region, tg.targetGroupName(), tg.targetGroupArn(), tg.loadBalancerArns().iterator().next(), |
| 361 | 357 | tg.protocol(), tg.port(), tg.healthCheckProtocol(), getHealthCheckPort(tg), tg.healthCheckPath())); |
| 362 | 358 | } |
| ... | ... | @@ -1244,10 +1240,11 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 1244 | 1240 | } |
| 1245 | 1241 | backgroundExecutor.shutdown(); |
| 1246 | 1242 | final Set<AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT>> result = new HashSet<>(); |
| 1243 | + final DNSCache dnsCache = getNewDNSCache(); |
|
| 1247 | 1244 | for (final Entry<String, ProcessT> serverNameAndMaster : mastersByServerName.entrySet()) { |
| 1248 | 1245 | final AwsApplicationReplicaSet<ShardingKey, MetricsT, ProcessT> replicaSet = new AwsApplicationReplicaSetImpl<ShardingKey, MetricsT, ProcessT>(serverNameAndMaster.getKey(), |
| 1249 | 1246 | serverNameAndMaster.getValue(), Optional.ofNullable(replicasByServerName.get(serverNameAndMaster.getKey())), |
| 1250 | - allLoadBalancersInRegion, allTargetGroupsInRegion, allLoadBalancerRulesInRegion); |
|
| 1247 | + allLoadBalancersInRegion, allTargetGroupsInRegion, allLoadBalancerRulesInRegion, this, dnsCache); |
|
| 1251 | 1248 | result.add(replicaSet); |
| 1252 | 1249 | } |
| 1253 | 1250 | return result; |
| ... | ... | @@ -1302,40 +1299,12 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 1302 | 1299 | return result; |
| 1303 | 1300 | } |
| 1304 | 1301 | |
| 1305 | - private <MetricsT extends ApplicationProcessMetrics, ProcessT extends ApplicationProcess<ShardingKey, MetricsT, ProcessT>> |
|
| 1306 | - String findHostnameForProcessThroughLoadBalancers(com.sap.sse.landscape.Region region, ProcessT process) { |
|
| 1307 | - final ApplicationLoadBalancer<ShardingKey> loadBalancer = findLoadBalancerForProcess(region, process); |
|
| 1308 | - // FIXME loadBalancer may be null / not found, especially when the process is served only through the reverse proxy, such as for the ARCHIVE server |
|
| 1309 | - String result; |
|
| 1310 | - if (loadBalancer == null) { |
|
| 1311 | - logger.info("Using default hostname for process running on "+process.getHost().getId()); |
|
| 1312 | - // FIXME this seems a strange default: |
|
| 1313 | - result = "www.sapsailing.com"; |
|
| 1314 | - } else { |
|
| 1315 | - result = null; |
|
| 1316 | - // FIXME many DNS entries may point to the same load balancer; how do we know it's the correct one? --> Disambiguation... |
|
| 1317 | - final String loadBalancerDNSName = loadBalancer.getDNSName(); |
|
| 1318 | - final Route53Client route53Client = getRoute53Client(); |
|
| 1319 | - outer: for (final HostedZone hostedZone : route53Client.listHostedZones().hostedZones()) { |
|
| 1320 | - ListResourceRecordSetsResponse resourceRecordSetsResponse = null; |
|
| 1321 | - do { |
|
| 1322 | - final ListResourceRecordSetsRequest.Builder resourceRecordSetsRequestBuilder = ListResourceRecordSetsRequest.builder(); |
|
| 1323 | - resourceRecordSetsRequestBuilder.hostedZoneId(hostedZone.id()); |
|
| 1324 | - if (resourceRecordSetsResponse != null) { |
|
| 1325 | - assert resourceRecordSetsResponse.isTruncated(); |
|
| 1326 | - resourceRecordSetsRequestBuilder.startRecordName(resourceRecordSetsResponse.nextRecordName()); |
|
| 1327 | - } |
|
| 1328 | - resourceRecordSetsResponse = route53Client.listResourceRecordSets(resourceRecordSetsRequestBuilder.build()); |
|
| 1329 | - for (final ResourceRecordSet resourceRecordSet : resourceRecordSetsResponse.resourceRecordSets()) { |
|
| 1330 | - if (resourceRecordSet.type() == RRType.CNAME && !Util.isEmpty(Util.filter(resourceRecordSet.resourceRecords(), rr->rr.value().equals(loadBalancerDNSName)))) { |
|
| 1331 | - result = resourceRecordSet.name().replaceFirst("\\.$", ""); // remove trailing dots |
|
| 1332 | - break outer; |
|
| 1333 | - } |
|
| 1334 | - } |
|
| 1335 | - } while (resourceRecordSetsResponse.isTruncated()); |
|
| 1336 | - } |
|
| 1337 | - } |
|
| 1338 | - return result; |
|
| 1302 | + @Override |
|
| 1303 | + public CompletableFuture<Iterable<ResourceRecordSet>> getResourceRecordSetsAsync(String hostname) { |
|
| 1304 | + final Route53AsyncClient route53Client = getRoute53AsyncClient(); |
|
| 1305 | + final String hostedZoneId = getDNSHostedZoneId(AwsLandscape.getHostedZoneName(hostname)); |
|
| 1306 | + return route53Client.listResourceRecordSets(b->b.hostedZoneId(hostedZoneId).startRecordName(hostname)).handle((response, e)-> |
|
| 1307 | + Util.filter(response.resourceRecordSets(), resourceRecordSet->resourceRecordSet.name().replaceFirst("\\.$", "").equals(hostname))); |
|
| 1339 | 1308 | } |
| 1340 | 1309 | |
| 1341 | 1310 | @Override |
| ... | ... | @@ -1400,15 +1369,18 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 1400 | 1369 | |
| 1401 | 1370 | @Override |
| 1402 | 1371 | public CompletableFuture<Map<TargetGroup<ShardingKey>, Iterable<TargetHealthDescription>>> getTargetGroupsAsync(com.sap.sse.landscape.Region region) { |
| 1403 | - // FIXME handle paging for large target groups response if nextMarker() is set in response; see also DescribeTargetGroupsResponseFetcher and ; see also describeTargetGroupsPaginator |
|
| 1404 | - return getLoadBalancingAsyncClient(getRegion(region)).describeTargetGroups().thenCompose(response->{ |
|
| 1372 | + final Set<DescribeTargetGroupsResponse> responses = new HashSet<>(); |
|
| 1373 | + return getLoadBalancingAsyncClient(getRegion(region)).describeTargetGroupsPaginator().subscribe(response->responses.add(response)).thenCompose(someVoid->{ |
|
| 1374 | + // now we have all responses |
|
| 1405 | 1375 | final Map<TargetGroup<ShardingKey>, CompletableFuture<Iterable<TargetHealthDescription>>> futures = new HashMap<>(); |
| 1406 | - for (final software.amazon.awssdk.services.elasticloadbalancingv2.model.TargetGroup tg : response.targetGroups()) { |
|
| 1407 | - final TargetGroup<ShardingKey> targetGroup = new AwsTargetGroupImpl<ShardingKey>(this, region, |
|
| 1408 | - tg.targetGroupName(), tg.targetGroupArn(), Util.first(tg.loadBalancerArns()), |
|
| 1409 | - tg.protocol(), tg.port(), tg.healthCheckProtocol(), getHealthCheckPort(tg), |
|
| 1410 | - tg.healthCheckPath()); |
|
| 1411 | - futures.put(targetGroup, getTargetHealthDescriptionsAsync(region, targetGroup)); |
|
| 1376 | + for (final DescribeTargetGroupsResponse response : responses) { |
|
| 1377 | + for (final software.amazon.awssdk.services.elasticloadbalancingv2.model.TargetGroup tg : response.targetGroups()) { |
|
| 1378 | + final TargetGroup<ShardingKey> targetGroup = new AwsTargetGroupImpl<ShardingKey>(this, region, |
|
| 1379 | + tg.targetGroupName(), tg.targetGroupArn(), Util.first(tg.loadBalancerArns()), |
|
| 1380 | + tg.protocol(), tg.port(), tg.healthCheckProtocol(), getHealthCheckPort(tg), |
|
| 1381 | + tg.healthCheckPath()); |
|
| 1382 | + futures.put(targetGroup, getTargetHealthDescriptionsAsync(region, targetGroup)); |
|
| 1383 | + } |
|
| 1412 | 1384 | } |
| 1413 | 1385 | return CompletableFuture.allOf(futures.values().toArray(new CompletableFuture<?>[0])).handle((v, e)->{ |
| 1414 | 1386 | final Map<TargetGroup<ShardingKey>, Iterable<TargetHealthDescription>> result = new HashMap<>(); |
| ... | ... | @@ -1424,25 +1396,6 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 1424 | 1396 | }); |
| 1425 | 1397 | } |
| 1426 | 1398 | |
| 1427 | - private <MetricsT extends ApplicationProcessMetrics, ProcessT extends ApplicationProcess<ShardingKey, MetricsT, ProcessT>> |
|
| 1428 | - ApplicationLoadBalancer<ShardingKey> findLoadBalancerForProcess(com.sap.sse.landscape.Region region, ProcessT process) { |
|
| 1429 | - for (final ApplicationLoadBalancer<ShardingKey> loadBalancer : getLoadBalancers(region)) { |
|
| 1430 | - for (final TargetGroup<ShardingKey> targetGroup : loadBalancer.getTargetGroups()) { |
|
| 1431 | - // first check that the target group is forwarding to the correct port: |
|
| 1432 | - // FIXME What about the case where the target group health-checks the targets through the HTTPS port through the reverse proxy? The "backward-compatible" case... |
|
| 1433 | - if (Util.equalsWithNull(targetGroup.getHealthCheckPort(), process.getPort())) { |
|
| 1434 | - // then check whether the process is part of targets registered: |
|
| 1435 | - final Optional<Entry<AwsInstance<ShardingKey>, TargetHealth>> target = targetGroup.getRegisteredTargets().entrySet().stream() |
|
| 1436 | - .filter(e->e.getKey().getInstanceId().equals(process.getHost().getId())).findAny(); |
|
| 1437 | - if (target.isPresent()) { |
|
| 1438 | - return loadBalancer; |
|
| 1439 | - } |
|
| 1440 | - } |
|
| 1441 | - } |
|
| 1442 | - } |
|
| 1443 | - return null; |
|
| 1444 | - } |
|
| 1445 | - |
|
| 1446 | 1399 | @Override |
| 1447 | 1400 | public AwsRegion getDefaultRegion() { |
| 1448 | 1401 | return new AwsRegion(Region.EU_WEST_2); // TODO actually, EU_WEST_1 (Ireland) is our default region, but as long as this is under development, EU_WEST_2 gives us an isolated test environment |
| ... | ... | @@ -1507,4 +1460,9 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 1507 | 1460 | final DescribeSnapshotsResponse describeSnapshotResponse = getEc2Client(getRegion(region)).describeSnapshots(b->b.filters(Filter.builder().name("snapshot-id").values(snapshotId).build())); |
| 1508 | 1461 | return describeSnapshotResponse.hasSnapshots() ? describeSnapshotResponse.snapshots().iterator().next() : null; |
| 1509 | 1462 | } |
| 1463 | + |
|
| 1464 | + @Override |
|
| 1465 | + public DNSCache getNewDNSCache() { |
|
| 1466 | + return new DNSCache(getRoute53AsyncClient()); |
|
| 1467 | + } |
|
| 1510 | 1468 | } |
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/DNSCache.java
| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | +package com.sap.sse.landscape.aws.impl; |
|
| 2 | + |
|
| 3 | +import java.util.concurrent.CompletableFuture; |
|
| 4 | +import java.util.concurrent.ConcurrentHashMap; |
|
| 5 | +import java.util.concurrent.ConcurrentLinkedQueue; |
|
| 6 | +import java.util.concurrent.ConcurrentMap; |
|
| 7 | + |
|
| 8 | +import com.sap.sse.common.Util; |
|
| 9 | +import com.sap.sse.landscape.aws.AwsLandscape; |
|
| 10 | + |
|
| 11 | +import software.amazon.awssdk.services.route53.Route53AsyncClient; |
|
| 12 | +import software.amazon.awssdk.services.route53.model.ResourceRecordSet; |
|
| 13 | + |
|
| 14 | +/** |
|
| 15 | + * When during landscape discovery several similar DNS requests are required, e.g., mapping a hosted zone |
|
| 16 | + * name to a hosted zone ID, or listing the resource record sets within a hosted zone, this cache can be used |
|
| 17 | + * to avoid repetitive requests. This cache has no invalidation logic. Toss it after your series of requests |
|
| 18 | + * is finished. |
|
| 19 | + * |
|
| 20 | + * @author Axel Uhl (D043530) |
|
| 21 | + * |
|
| 22 | + */ |
|
| 23 | +public class DNSCache { |
|
| 24 | + private final Route53AsyncClient route53Client; |
|
| 25 | + |
|
| 26 | + private final ConcurrentMap<String, CompletableFuture<String>> hostedZoneNamesToHostedZoneIds; |
|
| 27 | + |
|
| 28 | + private final ConcurrentMap<String, CompletableFuture<Iterable<ResourceRecordSet>>> hostedZoneIdsToResourceRecordSets; |
|
| 29 | + |
|
| 30 | + public DNSCache(Route53AsyncClient route53Client) { |
|
| 31 | + this.route53Client = route53Client; |
|
| 32 | + hostedZoneNamesToHostedZoneIds = new ConcurrentHashMap<>(); |
|
| 33 | + hostedZoneIdsToResourceRecordSets = new ConcurrentHashMap<>(); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + public CompletableFuture<String> getHostedZoneId(String hostedZoneName) { |
|
| 37 | + return hostedZoneNamesToHostedZoneIds.computeIfAbsent(hostedZoneName, |
|
| 38 | + hzn->route53Client.listHostedZonesByName(b->b.dnsName(hzn)).handle( |
|
| 39 | + (response, e)->response.hostedZones().iterator().next().id().replaceFirst("^\\/hostedzone\\/", ""))); |
|
| 40 | + } |
|
| 41 | + |
|
| 42 | + private CompletableFuture<Iterable<ResourceRecordSet>> getResourceRecordSets(String hostedZoneId) { |
|
| 43 | + final ConcurrentLinkedQueue<ResourceRecordSet> result = new ConcurrentLinkedQueue<>(); |
|
| 44 | + return hostedZoneIdsToResourceRecordSets.computeIfAbsent(hostedZoneId, hzid->{ |
|
| 45 | + return route53Client.listResourceRecordSetsPaginator(b->b.hostedZoneId(hzid)) |
|
| 46 | + .subscribe(rrs->result.addAll(rrs.resourceRecordSets())).handle((v, e)->result); |
|
| 47 | + }); |
|
| 48 | + } |
|
| 49 | + |
|
| 50 | + public CompletableFuture<Iterable<ResourceRecordSet>> getResourceRecordSetsAsync(String hostname) { |
|
| 51 | + return getHostedZoneId(AwsLandscape.getHostedZoneName(hostname)).thenCompose(hostedZoneId-> |
|
| 52 | + getResourceRecordSets(hostedZoneId)).handle((resourceRecordSets, e)-> |
|
| 53 | + Util.filter(resourceRecordSets, resourceRecordSet->resourceRecordSet.name().replaceFirst("\\.$", "").equals(hostname))); |
|
| 54 | + } |
|
| 55 | +} |
wiki/info/landscape/creating-ec2-image-from-scratch.md
| ... | ... | @@ -71,9 +71,11 @@ and added the lines |
| 71 | 71 | ``` |
| 72 | 72 | PermitRootLogin without-password |
| 73 | 73 | PermitRootLogin Yes |
| 74 | +MaxStartups 100 |
|
| 74 | 75 | ``` |
| 75 | 76 | |
| 76 | -to allow root shell login. |
|
| 77 | +to allow root shell login, and allow for several concurrent SSH connections (up to 100) starting up around the |
|
| 78 | +same time. |
|
| 77 | 79 | |
| 78 | 80 | I copied the JDK7/JDK8 installations, particularly the current sapjvm_8 VM, from an existing SL instance to /opt. |
| 79 | 81 |