app/collectors/zone.scala (114 lines of code) (raw):
package collectors
import agent._
import conf.AWS
import controllers.routes
import play.api.mvc.Call
import software.amazon.awssdk.services.route53.Route53Client
import software.amazon.awssdk.services.route53.model.{
HostedZone,
ListHostedZonesRequest,
ListResourceRecordSetsRequest,
ResourceRecordSet
}
import utils.Logging
import scala.jdk.CollectionConverters._
import scala.language.postfixOps
class Route53ZoneCollectorSet(accounts: Accounts)
extends CollectorSet[Route53Zone](
ResourceType("route53Zones"),
accounts,
Some(Global)
) {
val lookupCollector: PartialFunction[Origin, Collector[Route53Zone]] = {
case amazon: AmazonOrigin =>
Route53ZoneCollector(amazon, resource, amazon.crawlRate(resource.name))
}
}
case class Route53ZoneCollector(
origin: AmazonOrigin,
resource: ResourceType,
crawlRate: CrawlRate
) extends Collector[Route53Zone]
with Logging {
val client: Route53Client = Route53Client.builder
.credentialsProvider(origin.credentials.provider)
.region(origin.awsRegionV2)
.overrideConfiguration(AWS.clientConfig)
.build
def crawl: Iterable[Route53Zone] = {
client
.listHostedZonesPaginator(ListHostedZonesRequest.builder.build)
.hostedZones
.asScala
.map { zone =>
val records = client
.listResourceRecordSetsPaginator(
ListResourceRecordSetsRequest.builder.hostedZoneId(zone.id).build
)
.resourceRecordSets
.asScala
Route53Zone.fromApiData(zone, records, origin)
}
}
}
object Route53Zone {
def fromApiData(
zone: HostedZone,
awsRecordSets: Iterable[ResourceRecordSet],
origin: AmazonOrigin
): Route53Zone = {
val recordSets: List[Route53Record] = awsRecordSets.map { record =>
val alias = Option(record.aliasTarget).map(at =>
Route53Alias(at.dnsName, at.hostedZoneId, at.evaluateTargetHealth)
)
val maybeTtl: Option[Long] = Option(record.ttl).map(_.longValue)
val records = record.resourceRecords.asScala.map(_.value).toList
Route53Record(
record.name,
if (alias.nonEmpty) "ALIAS" else record.typeAsString,
maybeTtl,
if (records.isEmpty) None else Some(records),
alias
)
}.toList
val nameServers = recordSets
.filter(rs => rs.name == zone.name && rs.recordType == "NS")
.flatMap(_.records.getOrElse(Nil))
Route53Zone(
arn = s"arn:aws:route53:::hostedzone/${zone.id}",
name = zone.name,
id = zone.id,
callerReference = zone.callerReference,
comment = Option(zone.config.comment),
isPrivateZone = zone.config.privateZone,
resourceRecordSetCount = zone.resourceRecordSetCount,
nameServers = nameServers,
records = recordSets
)
}
}
case class Route53Alias(
dnsName: String,
hostedZoneId: String,
evaluateHealth: Boolean
)
case class Route53Record(
name: String,
recordType: String,
ttl: Option[Long],
records: Option[List[String]],
aliasTarget: Option[Route53Alias]
)
case class Route53Zone(
arn: String,
name: String,
id: String,
callerReference: String,
comment: Option[String],
isPrivateZone: Boolean,
resourceRecordSetCount: Long,
nameServers: List[String],
records: List[Route53Record]
) extends IndexedItem {
def callFromArn: (String) => Call = arn => routes.Api.route53Zone(arn)
}