Skip to content

Commit

Permalink
Fix errors in ApplicationAutoScaling models (#259)
Browse files Browse the repository at this point in the history
* add support for AWS::EC2::VPCEndpoint

* remove errant comma

* add dynamodb SSESpecification

* Adds support for PointInTimeRecoverySpecification

* Adds support for Tags

* Fix errors in ApplicationAutoScaling models

* - Added Description field to SecurityGroupIngress and SecurityGroupEgress.
- Changed StringBackedInt to Token[Int] for autoscaling group so that you can use parameters.
- AmazonTag.Key is now a token, so that you can use functions.

- Tested it with a real script:
https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html#eks-create-cluster - Step 3: point 5 (https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2018-08-30/amazon-eks-nodegroup.yaml)

* Fix unit tests:
- No longer use stringbackedint
- copied contents from generated extension file to non-generated extension file

* - Make Roles field in InstanceProfile to have tokens, so you can reference roles (instead of requiring you to always configure your own roles in the template).

* - Add EKS support and unit test.

* - Add GroupName support for security group.
- Make GroupDescription a Token type.

* - Add AssociateIpAddress field.

* Add additional parameters to AWS::EC2::VPCEndpoint

* cleanup AWS::ApplicationAutoScaling::ScalableTarget
  • Loading branch information
eanderson13 authored and tjcorr committed Jan 16, 2019
1 parent 247e708 commit c1ee37a
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.monsanto.arch.cloudformation.model.resource
import java.time.Instant

import com.monsanto.arch.cloudformation.model._
import com.monsanto.arch.cloudformation.model.resource.ApplicationAutoScaling.ScalableDimension
import spray.json._

object ApplicationAutoScaling {
Expand All @@ -26,10 +27,26 @@ object ApplicationAutoScaling {
implicit val format: JsonFormat[T] = jsonFormat5(apply)
}

sealed trait ScalingType extends Product with Serializable
sealed trait ServiceNamespace extends Product with Serializable

object ServiceNamespace extends DefaultJsonProtocol {
private type T = ServiceNamespace
case object appstream extends T
case object `custom-resource` extends T
case object dynamodb extends T
case object ec2 extends T
case object ecs extends T
case object elasticmapreduce extends T
case object rds extends T
case object sagemaker extends T
val values = Seq(appstream, `custom-resource`, dynamodb, ec2, ecs, elasticmapreduce, rds, sagemaker)
implicit val format: JsonFormat[T] = new EnumFormat[T](values)
}

sealed trait PolicyType extends Product with Serializable

object ScalingType extends DefaultJsonProtocol {
private type T = ScalingType
object PolicyType extends DefaultJsonProtocol {
private type T = PolicyType
case object StepScaling extends T
case object TargetTrackingScaling extends T
val values = Seq(StepScaling, TargetTrackingScaling)
Expand All @@ -47,6 +64,39 @@ object ApplicationAutoScaling {
implicit val format: JsonFormat[T] = new EnumFormat[T](values)
}


sealed trait ScalableDimension extends Product with Serializable

object ScalableDimension extends DefaultJsonProtocol {
private type T = ScalableDimension
case object `ecs:service:DesiredCount` extends T
case object `ec2:spot-fleet-request:TargetCapacity` extends T
case object `elasticmapreduce:instancegroup:InstanceCount` extends T
case object `appstream:fleet:DesiredCapacity` extends T
case object `dynamodb:table:ReadCapacityUnits` extends T
case object `dynamodb:table:WriteCapacityUnits` extends T
case object `dynamodb:index:ReadCapacityUnits` extends T
case object `dynamodb:index:WriteCapacityUnits` extends T
case object `rds:cluster:ReadReplicaCount` extends T
case object `sagemaker:variant:DesiredInstanceCount` extends T
case object `custom-resource:ResourceType:Property` extends T

val values = Seq(
`ecs:service:DesiredCount`,
`ec2:spot-fleet-request:TargetCapacity`,
`elasticmapreduce:instancegroup:InstanceCount`,
`appstream:fleet:DesiredCapacity`,
`dynamodb:table:ReadCapacityUnits`,
`dynamodb:table:WriteCapacityUnits`,
`dynamodb:index:ReadCapacityUnits`,
`dynamodb:index:WriteCapacityUnits`,
`rds:cluster:ReadReplicaCount`,
`sagemaker:variant:DesiredInstanceCount`,
`custom-resource:ResourceType:Property`
)
implicit val format: JsonFormat[T] = new EnumFormat[T](values)
}

case class StepAdjustment(MetricIntervalLowerBound: Option[Double] = None,
MetricIntervalUpperBound: Option[Double] = None,
ScalingAdjustment: Int) {
Expand Down Expand Up @@ -136,12 +186,14 @@ case class `AWS::ApplicationAutoScaling::ScalableTarget`(name: String,
MinCapacity: Token[Int],
ResourceId: Token[String],
RoleARN: Token[String],
ScalableDimension: Token[String],
ScalableDimension: ScalableDimension,
ScheduledActions: Option[Seq[ScheduledAction]] = None,
ServiceNamespace: `AWS::CloudWatch::Alarm::Namespace`,
ServiceNamespace: ApplicationAutoScaling.ServiceNamespace,
override val Condition: Option[ConditionRef] = None,
override val DependsOn : Option[Seq[String]] = None)
extends Resource[`AWS::ApplicationAutoScaling::ScalableTarget`] {
assert(ScalableDimension.toString.split(":").head == ServiceNamespace.toString, "ScalableDimension must match the ServiceNamespace")

def when(newCondition: Option[ConditionRef] = Condition) = copy(Condition = newCondition)
}

Expand All @@ -152,10 +204,10 @@ object `AWS::ApplicationAutoScaling::ScalableTarget` extends DefaultJsonProtocol

case class `AWS::ApplicationAutoScaling::ScalingPolicy`(name: String,
PolicyName: Token[String],
ScalingType: ApplicationAutoScaling.ScalingType,
PolicyType: ApplicationAutoScaling.PolicyType,
ResourceId: Option[Token[String]] = None,
ScalableDimension: Option[Token[String]] = None,
ScalingTargetId: Option[Token[String]] = None,
ScalingTargetId: Option[Token[ResourceRef[`AWS::ApplicationAutoScaling::ScalableTarget`]]] = None,
ServiceNamespace: Option[`AWS::CloudWatch::Alarm::Namespace`] = None,
StepScalingPolicyConfiguration: Option[ApplicationAutoScaling.StepScalingPolicyConfiguration] = None,
TargetTrackingScalingPolicyConfiguration: Option[ApplicationAutoScaling.TargetTrackingScalingPolicyConfiguration] = None,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.monsanto.arch.cloudformation.model.resource

import com.monsanto.arch.cloudformation.model.{JsonWritingMatcher, ResourceRef}
import org.scalatest.{FunSpec, Matchers}

class ApplicationAutoScaling_UT extends FunSpec with Matchers with JsonWritingMatcher {

val scalableTarget = `AWS::ApplicationAutoScaling::ScalableTarget`(
name = "myScalableTarget",
MaxCapacity = 100,
MinCapacity = 1,
ResourceId = "myResourceId",
RoleARN = "myRoleArn",
ScalableDimension = ApplicationAutoScaling.ScalableDimension.`custom-resource:ResourceType:Property`,
ServiceNamespace = ApplicationAutoScaling.ServiceNamespace.`custom-resource`)


it("should generate scalable target policy document") {

val resource: Resource[`AWS::ApplicationAutoScaling::ScalableTarget`] = scalableTarget

resource shouldMatch
"""
|{
| "Type": "AWS::ApplicationAutoScaling::ScalableTarget",
| "Properties": {
| "MaxCapacity": 100,
| "MinCapacity": 1,
| "ResourceId": "myResourceId",
| "RoleARN": "myRoleArn",
| "ScalableDimension": "custom-resource:ResourceType:Property",
| "ServiceNamespace": "custom-resource"
| }
|}
""".stripMargin
}

it("should error if ScalableDimension doesn't match the ServiceNamespace") {
an [java.lang.AssertionError] should be thrownBy
`AWS::ApplicationAutoScaling::ScalableTarget`(
name = "myScalableTarget",
MaxCapacity = 100,
MinCapacity = 1,
ResourceId = "myResourceId",
RoleARN = "myRoleArn",
ScalableDimension = ApplicationAutoScaling.ScalableDimension.`custom-resource:ResourceType:Property`,
ServiceNamespace = ApplicationAutoScaling.ServiceNamespace.dynamodb
)
}

it("should generate scaling policy document") {
val scalingPolicy = `AWS::ApplicationAutoScaling::ScalingPolicy`(
name = "myScalingPolicy",
PolicyName = "myPolicyName",
PolicyType = ApplicationAutoScaling.PolicyType.StepScaling,
ScalingTargetId = Some(ResourceRef(scalableTarget))
)

val resource: Resource[`AWS::ApplicationAutoScaling::ScalingPolicy`] = scalingPolicy

resource shouldMatch
"""
|{
| "Type": "AWS::ApplicationAutoScaling::ScalingPolicy",
| "Properties": {
| "PolicyName": "myPolicyName",
| "PolicyType": "StepScaling",
| "ScalingTargetId": { "Ref":"myScalableTarget" }
| }
|}
""".stripMargin
}
}

0 comments on commit c1ee37a

Please sign in to comment.