Repository: cloudtools/troposphere

Issue:
Add support for AWS::AutoScalingPlans::ScalingPlan
Hello,

I would like to see support for this type added. I will submit a PR with the code.

Thanks


Discussion:

Resolving patch:
diff --git a/troposphere/autoscalingplans.py b/troposphere/autoscalingplans.py
new file mode 100644
--- /dev/null
+++ b/troposphere/autoscalingplans.py
@@ -0,0 +1,87 @@
+# Copyright (c) 2012-2018, Mark Peek <mark@peek.org>
+# All rights reserved.
+#
+# See LICENSE file for full license.
+
+from . import AWSObject, AWSProperty
+from .validators import (boolean, double, integer, scalable_dimension_type,
+                         service_namespace_type, statistic_type)
+
+
+class TagFilter(AWSProperty):
+    props = {
+        'Values': ([basestring], False),
+        'Key': (basestring, True)
+    }
+
+
+class ApplicationSource(AWSProperty):
+    props = {
+        'CloudFormationStackARN': (basestring, False),
+        'TagFilters': ([TagFilter], False)
+    }
+
+
+class PredefinedScalingMetricSpecification(AWSProperty):
+    props = {
+        'ResourceLabel': (basestring, False),
+        'PredefinedScalingMetricType': (basestring, True)
+    }
+
+
+class MetricDimension(AWSProperty):
+    props = {
+        'Value': (basestring, True),
+        'Name': (basestring, True)
+    }
+
+
+class CustomizedScalingMetricSpecification(AWSProperty):
+    props = {
+        'MetricName': (basestring, True),
+        'Statistic': (statistic_type, True),
+        'Dimensions': ([MetricDimension], False),
+        'Unit': (basestring, False),
+        'Namespace': (basestring, True)
+    }
+
+
+class TargetTrackingConfiguration(AWSProperty):
+    props = {
+        'ScaleOutCooldown': (integer, False),
+        'TargetValue': (double, True),
+        'PredefinedScalingMetricSpecification': (
+            PredefinedScalingMetricSpecification,
+            False
+        ),
+        'DisableScaleIn': (boolean, False),
+        'ScaleInCooldown': (integer, False),
+        'EstimatedInstanceWarmup': (integer, False),
+        'CustomizedScalingMetricSpecification': (
+            CustomizedScalingMetricSpecification,
+            False
+        )
+    }
+
+
+class ScalingInstruction(AWSProperty):
+    props = {
+        'ResourceId': (basestring, True),
+        'ServiceNamespace': (service_namespace_type, True),
+        'ScalableDimension': (scalable_dimension_type, True),
+        'MinCapacity': (integer, True),
+        'TargetTrackingConfigurations': (
+            TargetTrackingConfiguration,
+            True
+        ),
+        'MaxCapacity': (integer, True)
+    }
+
+
+class ScalingPlan(AWSObject):
+    resource_type = "AWS::AutoScalingPlans::ScalingPlan"
+
+    props = {
+        'ApplicationSource': (ApplicationSource, True),
+        'ScalingInstructions': ([ScalingInstruction], True)
+    }
diff --git a/troposphere/validators.py b/troposphere/validators.py
--- a/troposphere/validators.py
+++ b/troposphere/validators.py
@@ -350,3 +350,46 @@ def vpc_endpoint_type(endpoint_type):
             )
         )
     return(endpoint_type)
+
+
+def scalable_dimension_type(scalable_dimension):
+    valid_values = ['autoscaling:autoScalingGroup:DesiredCapacity',
+                    'ecs:service:DesiredCount',
+                    'ec2:spot-fleet-request:TargetCapacity',
+                    'rds:cluster:ReadReplicaCount',
+                    'dynamodb:table:ReadCapacityUnits',
+                    'dynamodb:table:WriteCapacityUnits',
+                    'dynamodb:index:ReadCapacityUnits',
+                    'dynamodb:index:WriteCapacityUnits'
+                    ]
+    if scalable_dimension not in valid_values:
+        raise ValueError(
+            'ScalableDimension must be one of: "%s"' % (
+                ', '.join(valid_values)
+            )
+        )
+    return(scalable_dimension)
+
+
+def service_namespace_type(service_namespace):
+    valid_values = ['autoscaling', 'ecs', 'ec2', 'rds', 'dynamodb']
+    if service_namespace not in valid_values:
+        raise ValueError(
+            'ServiceNamespace must be one of: "%s"' % (
+                ', '.join(valid_values)
+            )
+        )
+    return(service_namespace)
+
+
+def statistic_type(statistic):
+    valid_values = ['Average', 'Minimum', 'Maximum',
+                    'SampleCount', 'Sum'
+                    ]
+    if statistic not in valid_values:
+        raise ValueError(
+            'Statistic must be one of: "%s"' % (
+                ', '.join(valid_values)
+            )
+        )
+    return(statistic)


Test patch: