in src/main/java/com/awslabs/aws/greengrass/provisioner/implementations/helpers/BasicDeploymentHelper.java [1351:1471]
private Optional<String> launchEc2Instance(String groupName, Architecture architecture, EC2LinuxVersion ec2LinuxVersion, int mqttPort, Set<Integer> openPorts) {
String instanceTagName = String.join("-", GREENGRASS_EC2_INSTANCE_TAG_PREFIX, groupName);
Optional<String> optionalAccountId = getAccountId(ec2LinuxVersion);
Optional<InstanceType> instanceType = getInstanceType(architecture);
Optional<String> optionalNameFilter = getNameFilter(architecture, ec2LinuxVersion);
if (!optionalAccountId.isPresent()) {
throw new RuntimeException(String.join("", "Unexpected EC2 Linux version requested [", ec2LinuxVersion.name(), "], this is a bug 1 [couldn't determine which AMI to use]"));
}
if (!optionalNameFilter.isPresent() || !instanceType.isPresent()) {
throw new RuntimeException(String.join("", "Unexpected architecture [", architecture.toString(), "] for EC2 launch"));
}
Optional<Image> optionalImage = getImage(optionalNameFilter.get(), optionalAccountId.get());
if (!optionalImage.isPresent()) {
log.error(String.join("", "No [", ec2LinuxVersion.name(), "] image found in this region, not launching the instance"));
return Optional.empty();
}
DescribeKeyPairsResponse describeKeyPairsResponse = ec2Client.describeKeyPairs();
// Find the first keypair
Optional<KeyPairInfo> optionalKeyPairInfo = describeKeyPairsResponse.keyPairs().stream().min(Comparator.comparing(KeyPairInfo::keyName));
if (!optionalKeyPairInfo.isPresent()) {
log.error("No SSH keys found in your account, not launching the instance");
return Optional.empty();
}
KeyPairInfo keyPairInfo = optionalKeyPairInfo.get();
log.warn(String.join("", "Automatically chose the first key pair available [", keyPairInfo.keyName(), "]"));
Image image = optionalImage.get();
String securityGroupName = String.join("-", instanceTagName, ioHelper.getUuid());
CreateSecurityGroupRequest createSecurityGroupRequest = CreateSecurityGroupRequest.builder()
.groupName(securityGroupName)
.description(String.join("", "Security group for Greengrass Core [", instanceTagName, "]"))
.build();
ec2Client.createSecurityGroup(createSecurityGroupRequest);
// Sometimes the security group isn't immediately visible so we need retries
RetryPolicy<AuthorizeSecurityGroupIngressResponse> securityGroupRetryPolicy = new RetryPolicy<AuthorizeSecurityGroupIngressResponse>()
.handleIf(throwable -> throwable.getMessage().contains(DOES_NOT_EXIST))
.withDelay(Duration.ofSeconds(5))
.withMaxRetries(6)
.onRetry(failure -> log.warn("Waiting for security group to become visible..."))
.onRetriesExceeded(failure -> log.error("Security group never became visible. Cannot continue."));
List<IpPermission> ipPermissions = openPorts.stream()
.map(this::openTcpPortToWorld)
.collect(Collectors.toList());
IpPermission sshPermission = openTcpPortToWorld(SSH_PORT);
IpPermission mqttPermission = openTcpPortToWorld(mqttPort);
IpPermission moshPermission = openUdpRangeToWorld(MOSH_START_PORT, MOSH_END_PORT);
ipPermissions.add(sshPermission);
ipPermissions.add(moshPermission);
ipPermissions.add(mqttPermission);
AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = AuthorizeSecurityGroupIngressRequest.builder()
.groupName(securityGroupName)
.ipPermissions(ipPermissions)
.build();
Failsafe.with(securityGroupRetryPolicy).get(() ->
ec2Client.authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest));
RunInstancesRequest runInstancesRequest = RunInstancesRequest.builder()
.imageId(image.imageId())
.instanceType(instanceType.get())
.maxCount(1)
.minCount(1)
.keyName(keyPairInfo.keyName())
.securityGroups(securityGroupName)
.build();
RunInstancesResponse runInstancesResponse = ec2Client.runInstances(runInstancesRequest);
Optional<String> optionalInstanceId = runInstancesResponse.instances().stream().findFirst().map(Instance::instanceId);
if (!optionalInstanceId.isPresent()) {
log.error("Couldn't find an instance ID, this should never happen, not launching the instance");
return Optional.empty();
}
String instanceId = optionalInstanceId.get();
Tag tag = Tag.builder()
.key("Name")
.value(instanceTagName)
.build();
CreateTagsRequest createTagsRequest = CreateTagsRequest.builder()
.tags(tag)
.resources(instanceId)
.build();
RetryPolicy<CreateTagsResponse> createTagsResponseRetryPolicy = new RetryPolicy<CreateTagsResponse>()
.handleIf(throwable -> throwable.getMessage().contains(DOES_NOT_EXIST))
.withDelay(Duration.ofSeconds(5))
.withMaxRetries(3)
.onRetry(failure -> log.warn("Instance may still be starting, trying again..."))
.onRetriesExceeded(failure -> log.error("Failed to find the instance in EC2, it was not launched"));
Failsafe.with(createTagsResponseRetryPolicy).get(() ->
ec2Client.createTags(createTagsRequest));
log.info(String.join("", "Launched instance [", instanceId, "] with tag [", instanceTagName, "]"));
return Optional.of(instanceId);
}