app/conf/AWS.scala (75 lines of code) (raw):
package conf
import java.net.InetAddress
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration
import software.amazon.awssdk.core.retry.RetryMode
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.regions.internal.util.EC2MetadataUtils
import software.amazon.awssdk.services.ec2.Ec2Client
import software.amazon.awssdk.services.ec2.model.{
DescribeInstancesRequest,
DescribeTagsRequest,
Filter
}
import utils.Logging
import scala.collection.MapView
import scala.jdk.CollectionConverters._
import scala.util.Try
object AWS extends Logging {
val clientConfig: ClientOverrideConfiguration = ClientOverrideConfiguration
.builder()
.retryStrategy(RetryMode.ADAPTIVE_V2)
.build()
// This is to detect if we are running in AWS or on GC2. The 169.254.169.254
// thing works on both but this DNS entry seems peculiar to AWS.
lazy val isAWS: Boolean = Try(
InetAddress.getByName("instance-data")
).isSuccess
def awsOption[T](f: => T): Option[T] = if (isAWS) Option(f) else None
lazy val connectionRegion: Region = Region.EU_WEST_1
lazy val EC2Client: Ec2Client = Ec2Client
.builder()
.region(connectionRegion)
.overrideConfiguration(clientConfig)
.build()
type Tag = (String, String)
object instance {
lazy val id: Option[String] = awsOption(EC2MetadataUtils.getInstanceId)
lazy val allTags: Map[String, String] =
id.toSeq.flatMap { id =>
val tagsResult = AWS.EC2Client.describeTags(
DescribeTagsRequest.builder
.filters(
Filter.builder.name("resource-type").values("instance").build,
Filter.builder.name("resource-id").values(id).build
)
.build
)
tagsResult.tags.asScala.map(td => td.key -> td.value)
}.toMap
lazy val customTags: MapView[String, String] =
allTags.view.filterKeys(!_.startsWith("aws:"))
lazy val identity: Option[Identity] = (
customTags.get("Stack"),
customTags.get("App"),
customTags.get("Stage")
) match {
case (Some(stack), Some(app), Some(stage)) =>
Some(Identity(stack, app, stage))
case _ => None
}
}
object instanceLookup {
def addressesFromTags(tags: List[Tag]): List[String] = {
log.info(s"Looking up instances with tags: $tags")
val tagsAsFilters = tags.map { case (name, value) =>
Filter.builder.name("tag:" + name).values(value).build
}.asJavaCollection
val describeInstancesResult = EC2Client.describeInstances(
DescribeInstancesRequest.builder.filters(tagsAsFilters).build
)
val reservation = describeInstancesResult.reservations.asScala.toList
val instances = reservation.flatMap(r => r.instances.asScala)
val addresses = instances.flatMap(i => Option(i.privateIpAddress))
log.info(s"Instances with tags $tags: $addresses")
addresses
}
}
}