app/controllers/AMIable.scala (129 lines of code) (raw):
package controllers
import com.gu.googleauth.AuthAction
import config.{AMIableConfig, AmiableConfigProvider}
import metrics.Charts
import models._
import play.api._
import play.api.mvc._
import prism.{Prism, PrismLogic, Recommendations}
import services.Agents
import services.notification.Notifications
import scala.concurrent.ExecutionContext
class AMIable(
val controllerComponents: ControllerComponents,
val amiableConfigProvider: AmiableConfigProvider,
agents: Agents,
notifications: Notifications,
authAction: AuthAction[AnyContent]
)(implicit exec: ExecutionContext)
extends BaseController
with Logging {
implicit val conf: AMIableConfig = amiableConfigProvider.conf
def index: Action[AnyContent] = authAction.async { implicit request =>
val ssaa = SSAA()
val charts = Charts.charts(
instanceCountHistory = agents.oldProdInstanceCountHistory,
age25thPercentileHistory = agents.amisAgePercentile25thHistory,
age50thPercentileHistory = agents.amisAgePercentile50thHistory,
age75thPercentileHistory = agents.amisAgePercentile75thHistory
)
attempt {
for {
instancesWithAmis <- Prism.instancesWithAmis(ssaa)
accountNames <- Prism.getAccounts
oldInstances = PrismLogic.oldInstances(instancesWithAmis)
oldStacks = PrismLogic.stacks(oldInstances)
agePercentiles = PrismLogic.instancesAmisAgePercentiles(
instancesWithAmis
)
metrics = Metrics(
oldInstances.length,
instancesWithAmis.length,
agePercentiles
)
} yield Ok(
views.html.index(
oldStacks.sorted,
charts,
metrics,
accountNames.map(_.accountName)
)
)
}
}
def ami(imageId: String): Action[AnyContent] = authAction.async {
implicit request =>
attempt {
for {
amis <- Prism.getAMIs()
ami <- AMI.extract(imageId, amis)
amiWithUpgrade = Recommendations.amiWithUpgrade(agents.allAmis)(ami)
instances <- Prism.imageUsage(ami)
launchConfigs <- Prism.launchConfigUsage(ami)
} yield Ok(
views.html.ami(
amiWithUpgrade,
conf,
PrismLogic.sortInstancesByStack(instances),
PrismLogic.sortLCsByOwner(launchConfigs)
)
)
}
}
def ssaInstanceAMIs(
stackOpt: Option[String],
stageOpt: Option[String],
appOpt: Option[String],
accountNameOpt: Option[String]
): Action[AnyContent] = authAction.async { implicit request =>
val ssaa = SSAA.fromParams(stackOpt, stageOpt, appOpt, accountNameOpt)
attempt {
for {
instancesWithAmis <- Prism.instancesWithAmis(ssaa)
accounts <- Prism.getAccounts
instances = instancesWithAmis.map(_._1)
amis = instancesWithAmis.flatMap(_._2).distinct
amisWithUpgrades = amis.map(
Recommendations.amiWithUpgrade(agents.allAmis)
)
amisWithInstances = PrismLogic.amiInstances(amisWithUpgrades, instances)
oldInstances = PrismLogic.oldInstances(instancesWithAmis)
amiSSAs = PrismLogic.amiSSAAs(amisWithInstances)
metrics = Metrics(
oldInstancesCount = oldInstances.length,
totalInstancesCount = instances.length,
PrismLogic.instancesAmisAgePercentiles(instancesWithAmis)
)
allSSAs = ssaa :: PrismLogic.instanceSSAAs(instances)
instancesCount = PrismLogic.instancesCountPerSsaPerAmi(
amisWithInstances,
allSSAs
)
accountNames = accounts.map(_.accountName)
} yield Ok(
views.html.instanceAMIs(
ssaa,
metrics,
amisWithUpgrades.sortBy(_.creationDate.map(_.getMillis)),
PrismLogic.sortSSAAmisByAge(amiSSAs),
instancesCount,
accountNames,
conf
)
)
}
}
def sendEmail: Action[AnyContent] = authAction.async {
attempt {
for {
emailIds <- notifications.sendEmail()
} yield Ok(s"Emails sent (ids):\n ${emailIds.mkString("\n")}")
}
}
/** `Attempt` with nicely formatted error handling using the error template
*/
private def attempt[A](action: => Attempt[Result]) = {
Attempt(action) { err =>
logger.error(err.logString)
Status(err.statusCode)(views.html.error(err))
}
}
}