app/collectors/reservation.scala (111 lines of code) (raw):
package collectors
import java.time.Instant
import agent._
import conf.AWS
import controllers.routes
import play.api.mvc.Call
import software.amazon.awssdk.services.ec2.Ec2Client
import software.amazon.awssdk.services.ec2.model.{
DescribeReservedInstancesRequest,
ReservedInstances,
RecurringCharge => AwsRecurringCharge
}
import utils.Logging
import scala.jdk.CollectionConverters._
import scala.language.postfixOps
class ReservationCollectorSet(accounts: Accounts)
extends CollectorSet[Reservation](
ResourceType("reservation"),
accounts,
Some(Regional)
) {
val lookupCollector: PartialFunction[Origin, Collector[Reservation]] = {
case amazon: AmazonOrigin =>
AWSReservationCollector(amazon, resource, amazon.crawlRate(resource.name))
}
}
case class AWSReservationCollector(
origin: AmazonOrigin,
resource: ResourceType,
crawlRate: CrawlRate
) extends Collector[Reservation]
with Logging {
val client = Ec2Client.builder
.credentialsProvider(origin.credentials.provider)
.region(origin.awsRegionV2)
.overrideConfiguration(AWS.clientConfig)
.build
def crawl: Iterable[Reservation] = {
client
.describeReservedInstances(DescribeReservedInstancesRequest.builder.build)
.reservedInstances
.asScala
.map {
Reservation.fromApiData(_, origin)
}
}
}
case class Reservation(
arn: String,
id: String,
region: String,
instanceType: String,
instanceCount: Int,
productDescription: String,
fixedPrice: Float,
usagePrice: Float,
recurringCharges: List[RecurringCharge],
state: String,
currencyCode: String,
duration: Long,
instanceTenancy: String,
offeringType: String,
startTime: Instant,
endTime: Instant
) extends IndexedItem {
override def callFromArn: (String) => Call = arn =>
routes.Api.reservation(arn)
}
object Reservation {
def fromApiData(
reservationInstance: ReservedInstances,
origin: AmazonOrigin
): Reservation = {
val region = reservationInstance.availabilityZone
val arn =
s"arn:aws:ec2:$region:${origin.accountNumber.getOrElse("")}:reservation/${reservationInstance.reservedInstancesId}"
val recurringCharges = reservationInstance.recurringCharges.asScala
.map(RecurringCharge.fromApiData)
.toList
Reservation(
arn = arn,
id = reservationInstance.reservedInstancesId,
region = region,
instanceType = reservationInstance.instanceTypeAsString,
instanceCount = reservationInstance.instanceCount,
productDescription = reservationInstance.productDescriptionAsString,
fixedPrice = reservationInstance.fixedPrice,
usagePrice = reservationInstance.usagePrice,
recurringCharges = recurringCharges,
state = reservationInstance.stateAsString,
currencyCode = reservationInstance.currencyCodeAsString,
duration = reservationInstance.duration,
instanceTenancy = reservationInstance.instanceTenancyAsString,
offeringType = reservationInstance.offeringTypeAsString,
startTime = reservationInstance.start,
endTime = reservationInstance.end
)
}
}
case class RecurringCharge(
frequency: String,
amount: Double
)
object RecurringCharge {
def fromApiData(recurringCharge: AwsRecurringCharge): RecurringCharge = {
RecurringCharge(
frequency = recurringCharge.frequencyAsString,
amount = recurringCharge.amount
)
}
}