app/config/AWS.scala (72 lines of code) (raw):

package config import com.amazonaws.auth.profile.ProfileCredentialsProvider import com.amazonaws.auth.{AWSCredentialsProviderChain, EnvironmentVariableCredentialsProvider, InstanceProfileCredentialsProvider, SystemPropertiesCredentialsProvider} import com.amazonaws.regions.{Region, Regions} import com.amazonaws.services.autoscaling.{AmazonAutoScaling, AmazonAutoScalingClientBuilder} import com.amazonaws.services.autoscaling.model.{DescribeAutoScalingGroupsRequest, DescribeAutoScalingInstancesRequest} import com.amazonaws.services.s3.{AmazonS3, AmazonS3ClientBuilder} import com.amazonaws.services.simpleemail.{AmazonSimpleEmailService, AmazonSimpleEmailServiceClientBuilder} import com.amazonaws.services.simplesystemsmanagement.{AWSSimpleSystemsManagement, AWSSimpleSystemsManagementClientBuilder} import com.amazonaws.util.EC2MetadataUtils import software.amazon.awssdk.services.dynamodb.DynamoDbClient import software.amazon.awssdk.regions.{Region => RegionV2} import software.amazon.awssdk.auth.credentials.{ AwsCredentialsProviderChain, EnvironmentVariableCredentialsProvider => EnvironmentVariableCredentialsProviderV2, InstanceProfileCredentialsProvider => InstanceProfileCredentialsProviderV2, ProfileCredentialsProvider => ProfileCredentialsProviderV2 } import scala.jdk.CollectionConverters._ case class InstanceTags(stack: String, app: String, stage: String) class AWS { val region = Region.getRegion(Regions.EU_WEST_1).getName val profile = "composer" val composerAwsCredentialsProvider = new AWSCredentialsProviderChain( new EnvironmentVariableCredentialsProvider(), new SystemPropertiesCredentialsProvider(), InstanceProfileCredentialsProvider.getInstance(), new ProfileCredentialsProvider(profile) ) val asgClient: AmazonAutoScaling = AmazonAutoScalingClientBuilder.standard().withRegion(region).withCredentials(composerAwsCredentialsProvider).build() val ssmClient: AWSSimpleSystemsManagement = AWSSimpleSystemsManagementClientBuilder.standard().withRegion(region).withCredentials(composerAwsCredentialsProvider).build() val s3Client: AmazonS3 = AmazonS3ClientBuilder.standard().withRegion(region).withCredentials(composerAwsCredentialsProvider).build() val sesClient: AmazonSimpleEmailService = AmazonSimpleEmailServiceClientBuilder.standard().withRegion(region).withCredentials(composerAwsCredentialsProvider).build() private val v2CredentialsProvider = AwsCredentialsProviderChain.builder.credentialsProviders( ProfileCredentialsProviderV2.builder.profileName(profile).build, InstanceProfileCredentialsProviderV2.builder.asyncCredentialUpdateEnabled(false).build, EnvironmentVariableCredentialsProviderV2.create() ).build val dynamoDbClient: DynamoDbClient = DynamoDbClient.builder .credentialsProvider(v2CredentialsProvider) .region(RegionV2.EU_WEST_1) .build() def readTags(): Option[InstanceTags] = { // We read tags from the AutoScalingGroup rather than the instance itself to avoid problems where the // tags have not been applied to the instance before we start up (they are eventually consistent) for { instanceId <- Option(EC2MetadataUtils.getInstanceId) asg <- getAutoscalingGroupName(instanceId) tags <- getTags(asg) stack <- tags.get("Stack") app <- tags.get("App") stage <- tags.get("Stage") } yield { InstanceTags(stack, app, stage) } } private def getAutoscalingGroupName(instanceId: String): Option[String] = { val request = new DescribeAutoScalingInstancesRequest().withInstanceIds(instanceId) val response = asgClient.describeAutoScalingInstances(request) val instance = response.getAutoScalingInstances.asScala.headOption instance.map(_.getAutoScalingGroupName) } private def getTags(autoscalingGroupName: String): Option[Map[String, String]] = { val request = new DescribeAutoScalingGroupsRequest().withAutoScalingGroupNames(autoscalingGroupName) val response = asgClient.describeAutoScalingGroups(request) val maybeGroup = response.getAutoScalingGroups.asScala.headOption maybeGroup.map { _.getTags .asScala .map { t => t.getKey -> t.getValue } .toMap } } }