app/models/models.scala (173 lines of code) (raw):
package models
import org.joda.time.DateTime
import play.api.libs.json._
import utils.{DateUtils, Percentiles}
import play.api.libs.json.JodaWrites._
import play.api.libs.json.JodaReads._
case class AMI(
arn: String,
name: Option[String],
imageId: String,
region: String,
description: Option[String],
tags: Map[String, String],
creationDate: Option[DateTime],
state: String,
architecture: String,
ownerId: String,
virtualizationType: String,
hypervisor: String,
rootDeviceType: String,
sriovNetSupport: Option[String],
upgrade: Option[AMI] = None
) {
override def toString: String = s"AMI<$arn>"
}
object AMI {
import utils.DateUtils._
implicit val jsonFormat: Format[AMI] = Json.format[AMI]
def extract(imageId: String, amis: List[AMI]): Attempt[AMI] = {
val imageOpt = amis.find(_.imageId == imageId)
Attempt.fromOption(
imageOpt,
AMIableErrors(
AMIableError(
s"Could not find image with id: $imageId",
s"Could not find image with id: $imageId",
404
)
)
)
}
}
case class Instance(
arn: String,
name: String,
vendorState: String,
group: String,
dnsName: String,
ip: String,
createdAt: DateTime,
instanceName: String,
region: String,
vendor: String,
securityGroups: List[String],
tags: Map[String, String],
stack: Option[String],
stage: Option[String],
app: List[String],
mainclasses: List[String],
specification: Map[String, String],
meta: Meta
) {
val amiArn = specification.get("imageArn")
override def toString: String = s"Instance<$arn>"
}
case class Origin(
vendor: String,
accountName: Option[String],
region: String,
accountNumber: String
)
object Origin {
implicit val jsonFormat: Format[Origin] = Json.format[Origin]
}
case class Meta(
href: String,
origin: Origin
)
object Meta {
implicit val jsonFormat: Format[Meta] = Json.format[Meta]
}
case class SSAA(
stack: Option[String] = None,
stage: Option[String] = None,
app: Option[String] = None,
accountName: Option[String] = None
) {
def isEmpty = stack.isEmpty && stage.isEmpty && app.isEmpty
override def toString: String = {
// accountName is non optional in some cases so is often set to "". In these cases treat it as 'none'
val accountString =
if (accountName.isEmpty || accountName.contains("")) "unknown-account"
else accountName.get
s"SSAA<${stack.getOrElse("none")}, ${stage.getOrElse("none")}, ${app
.getOrElse("none")}, ${accountString}>"
}
}
object SSAA {
implicit val jsonFormat: Format[SSAA] = Json.format[SSAA]
/** Filters empty strings to None, such as those provided by request
* parameters.
*/
def fromParams(
stack: Option[String] = None,
stage: Option[String] = None,
app: Option[String] = None,
accountName: Option[String] = None
): SSAA =
SSAA(
stack.filter(_.nonEmpty),
stage.filter(_.nonEmpty),
app.filter(_.nonEmpty),
accountName.filter(_.nonEmpty)
)
def empty = SSAA(None, None, None, None)
def riffRaffLink(ssaa: SSAA, region: String): Option[String] = for {
stack <- ssaa.stack
stage <- ssaa.stage
app <- ssaa.app
} yield {
s"https://riffraff.gutools.co.uk/deployment/target/deploy?region=$region&stack=$stack&stage=$stage&app=$app"
}
}
case class AMIableError(
message: String,
friendlyMessage: String,
statusCode: Int,
context: Option[String] = None
)
sealed trait Age
object Fresh extends Age
object Turning extends Age
object Old extends Age
case class Metrics(
oldInstancesCount: Int,
totalInstancesCount: Int,
agePercentiles: Percentiles
)
case class ChartTimeSerie(
label: String,
data: List[(DateTime, Double)],
color: String = ""
)
case class Chart(title: String, data: List[ChartTimeSerie]) {
val id = title.hashCode
}
case class LaunchConfiguration(
arn: String,
name: String,
imageId: String,
region: String,
createdTime: DateTime,
instanceType: String,
keyName: String,
securityGroups: List[String],
userData: Option[String],
meta: Meta
)
object LaunchConfiguration {
import utils.DateUtils._
implicit val jsonFormat: Format[LaunchConfiguration] =
Json.format[LaunchConfiguration]
}
case class Owner(id: String, stacks: List[SSAA]) {
def hasSSA(ssaa: SSAA): Boolean = stacks.contains(ssaa)
}
object Owner {
implicit val jsonFormat: Format[Owner] = Json.format[Owner]
}
case class Owners(owners: List[Owner], defaultOwner: Owner)
object Owners {
implicit val jsonFormat: Format[Owners] = Json.format[Owners]
}
case class AWSAccount(accountNumber: Option[String], accountName: String)
object AWSAccount {
implicit val jsonFormat: Format[AWSAccount] = Json.format[AWSAccount]
}