-
Notifications
You must be signed in to change notification settings - Fork 9.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
resource/aws_autoscaling_policy: Add support for target_tracking_configuration #2611
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ func resourceAwsAutoscalingPolicy() *schema.Resource { | |
}, | ||
"adjustment_type": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
Optional: true, | ||
}, | ||
"autoscaling_group_name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
|
@@ -93,6 +93,81 @@ func resourceAwsAutoscalingPolicy() *schema.Resource { | |
}, | ||
Set: resourceAwsAutoscalingScalingAdjustmentHash, | ||
}, | ||
"target_tracking_configuration": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"predefined_metric_specification": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise - as above ^ |
||
Optional: true, | ||
ConflictsWith: []string{"target_tracking_configuration.customized_metric_specification"}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this won't actually work, because the address isn't correct. The real address would be |
||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"predefined_metric_type": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"resource_label": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"customized_metric_specification": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise - as above ^ |
||
Optional: true, | ||
ConflictsWith: []string{"target_tracking_configuration.predefined_metric_specification"}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise - as above ^ |
||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"metric_dimension": &schema.Schema{ | ||
Type: schema.TypeList, | ||
Optional: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"value": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"metric_name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"namespace": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"statistic": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"unit": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"target_value": &schema.Schema{ | ||
Type: schema.TypeFloat, | ||
Required: true, | ||
}, | ||
"disable_scale_in": &schema.Schema{ | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Default: false, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
@@ -146,6 +221,7 @@ func resourceAwsAutoscalingPolicyRead(d *schema.ResourceData, meta interface{}) | |
d.Set("name", p.PolicyName) | ||
d.Set("scaling_adjustment", p.ScalingAdjustment) | ||
d.Set("step_adjustment", flattenStepAdjustments(p.StepAdjustments)) | ||
d.Set("target_tracking_configuration", flattenTargetTrackingConfiguration(p.TargetTrackingConfiguration)) | ||
|
||
return nil | ||
} | ||
|
@@ -240,6 +316,10 @@ func getAwsAutoscalingPutScalingPolicyInput(d *schema.ResourceData) (autoscaling | |
params.MinAdjustmentStep = aws.Int64(int64(v.(int))) | ||
} | ||
|
||
if v, ok := d.GetOk("target_tracking_configuration"); ok { | ||
params.TargetTrackingConfiguration = expandTargetTrackingConfiguration(v.(*schema.Set).List()[0].(map[string]interface{})) | ||
} | ||
|
||
// Validate our final input to confirm it won't error when sent to AWS. | ||
// First, SimpleScaling policy types... | ||
if *params.PolicyType == "SimpleScaling" && params.StepAdjustments != nil { | ||
|
@@ -251,6 +331,9 @@ func getAwsAutoscalingPutScalingPolicyInput(d *schema.ResourceData) (autoscaling | |
if *params.PolicyType == "SimpleScaling" && params.EstimatedInstanceWarmup != nil { | ||
return params, fmt.Errorf("SimpleScaling policy types cannot use estimated_instance_warmup!") | ||
} | ||
if *params.PolicyType == "SimpleScaling" && params.TargetTrackingConfiguration != nil { | ||
return params, fmt.Errorf("SimpleScaling policy types cannot use target_tracking_configuration!") | ||
} | ||
|
||
// Second, StepScaling policy types... | ||
if *params.PolicyType == "StepScaling" && params.ScalingAdjustment != nil { | ||
|
@@ -259,6 +342,29 @@ func getAwsAutoscalingPutScalingPolicyInput(d *schema.ResourceData) (autoscaling | |
if *params.PolicyType == "StepScaling" && params.Cooldown != nil { | ||
return params, fmt.Errorf("StepScaling policy types cannot use cooldown!") | ||
} | ||
if *params.PolicyType == "StepScaling" && params.TargetTrackingConfiguration != nil { | ||
return params, fmt.Errorf("StepScaling policy types cannot use target_tracking_configuration!") | ||
} | ||
|
||
// Third, TargetTrackingScaling policy types... | ||
if *params.PolicyType == "TargetTrackingScaling" && params.AdjustmentType != nil { | ||
return params, fmt.Errorf("TargetTrackingScaling policy types cannot use adjustment_type!") | ||
} | ||
if *params.PolicyType == "TargetTrackingScaling" && params.Cooldown != nil { | ||
return params, fmt.Errorf("TargetTrackingScaling policy types cannot use cooldown!") | ||
} | ||
if *params.PolicyType == "TargetTrackingScaling" && params.MetricAggregationType != nil { | ||
return params, fmt.Errorf("TargetTrackingScaling policy types cannot use metric_aggregation_type!") | ||
} | ||
if *params.PolicyType == "TargetTrackingScaling" && params.MinAdjustmentMagnitude != nil { | ||
return params, fmt.Errorf("TargetTrackingScaling policy types cannot use min_adjustment_magnitude!") | ||
} | ||
if *params.PolicyType == "TargetTrackingScaling" && params.ScalingAdjustment != nil { | ||
return params, fmt.Errorf("TargetTrackingScaling policy types cannot use scaling_adjustment!") | ||
} | ||
if *params.PolicyType == "TargetTrackingScaling" && params.StepAdjustments != nil { | ||
return params, fmt.Errorf("TargetTrackingScaling policy types cannot use step_adjustments!") | ||
} | ||
|
||
return params, nil | ||
} | ||
|
@@ -309,3 +415,84 @@ func resourceAwsAutoscalingScalingAdjustmentHash(v interface{}) int { | |
|
||
return hashcode.String(buf.String()) | ||
} | ||
|
||
func expandTargetTrackingConfiguration(config map[string]interface{}) *autoscaling.TargetTrackingConfiguration { | ||
result := &autoscaling.TargetTrackingConfiguration{} | ||
|
||
result.TargetValue = aws.Float64(config["target_value"].(float64)) | ||
if v, ok := config["disable_scale_in"]; ok { | ||
result.DisableScaleIn = aws.Bool(v.(bool)) | ||
} | ||
if v, ok := config["predefined_metric_specification"]; ok && len(v.(*schema.Set).List()) > 0 { | ||
spec := v.(*schema.Set).List()[0].(map[string]interface{}) | ||
predSpec := &autoscaling.PredefinedMetricSpecification{ | ||
PredefinedMetricType: aws.String(spec["predefined_metric_type"].(string)), | ||
} | ||
if val, ok := spec["resource_label"]; ok && val.(string) != "" { | ||
predSpec.ResourceLabel = aws.String(val.(string)) | ||
} | ||
result.PredefinedMetricSpecification = predSpec | ||
} | ||
if v, ok := config["customized_metric_specification"]; ok && len(v.(*schema.Set).List()) > 0 { | ||
spec := v.(*schema.Set).List()[0].(map[string]interface{}) | ||
customSpec := &autoscaling.CustomizedMetricSpecification{ | ||
Namespace: aws.String(spec["namespace"].(string)), | ||
MetricName: aws.String(spec["metric_name"].(string)), | ||
Statistic: aws.String(spec["statistic"].(string)), | ||
} | ||
if val, ok := spec["unit"]; ok { | ||
customSpec.Unit = aws.String(val.(string)) | ||
} | ||
if val, ok := spec["metric_dimension"]; ok { | ||
dims := val.([]interface{}) | ||
metDimList := make([]*autoscaling.MetricDimension, len(dims)) | ||
for i := range metDimList { | ||
dim := dims[i].(map[string]interface{}) | ||
md := &autoscaling.MetricDimension{ | ||
Name: aws.String(dim["name"].(string)), | ||
Value: aws.String(dim["value"].(string)), | ||
} | ||
metDimList[i] = md | ||
} | ||
customSpec.Dimensions = metDimList | ||
} | ||
result.CustomizedMetricSpecification = customSpec | ||
} | ||
return result | ||
} | ||
|
||
func flattenTargetTrackingConfiguration(config *autoscaling.TargetTrackingConfiguration) []map[string]interface{} { | ||
result := map[string]interface{}{} | ||
result["disable_scale_in"] = *config.DisableScaleIn | ||
result["target_value"] = *config.TargetValue | ||
if config.PredefinedMetricSpecification != nil { | ||
spec := map[string]interface{}{} | ||
spec["predefined_metric_type"] = *config.PredefinedMetricSpecification.PredefinedMetricType | ||
if config.PredefinedMetricSpecification.ResourceLabel != nil { | ||
spec["resource_label"] = *config.PredefinedMetricSpecification.ResourceLabel | ||
} | ||
result["predefined_metric_specification"] = []map[string]interface{}{spec} | ||
} | ||
if config.CustomizedMetricSpecification != nil { | ||
spec := map[string]interface{}{} | ||
spec["metric_name"] = *config.CustomizedMetricSpecification.MetricName | ||
spec["namespace"] = *config.CustomizedMetricSpecification.Namespace | ||
spec["statistic"] = *config.CustomizedMetricSpecification.Statistic | ||
if config.CustomizedMetricSpecification.Unit != nil { | ||
spec["unit"] = *config.CustomizedMetricSpecification.Unit | ||
} | ||
if config.CustomizedMetricSpecification.Dimensions != nil { | ||
dimSpec := make([]interface{}, len(config.CustomizedMetricSpecification.Dimensions)) | ||
for i := range dimSpec { | ||
dim := map[string]interface{}{} | ||
rawDim := config.CustomizedMetricSpecification.Dimensions[i] | ||
dim["name"] = *rawDim.Name | ||
dim["value"] = *rawDim.Value | ||
dimSpec[i] = dim | ||
} | ||
spec["metric_dimension"] = dimSpec | ||
} | ||
result["customized_metric_specification"] = []map[string]interface{}{spec} | ||
} | ||
return []map[string]interface{}{result} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,6 +140,46 @@ func TestAccAWSAutoscalingPolicy_upgrade(t *testing.T) { | |
}) | ||
} | ||
|
||
func TestAccAWSAutoscalingPolicy_TargetTrack_Predefined(t *testing.T) { | ||
var policy autoscaling.ScalingPolicy | ||
|
||
name := acctest.RandString(5) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckAWSAutoscalingPolicyDestroy, | ||
Steps: []resource.TestStep{ | ||
resource.TestStep{ | ||
Config: testAccAwsAutoscalingPolicyConfig_TargetTracking_Predefined(name), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckScalingPolicyExists("aws_autoscaling_policy.test", &policy), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccAWSAutoscalingPolicy_TargetTrack_Custom(t *testing.T) { | ||
var policy autoscaling.ScalingPolicy | ||
|
||
name := acctest.RandString(5) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckAWSAutoscalingPolicyDestroy, | ||
Steps: []resource.TestStep{ | ||
resource.TestStep{ | ||
Config: testAccAwsAutoscalingPolicyConfig_TargetTracking_Custom(name), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckScalingPolicyExists("aws_autoscaling_policy.test", &policy), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckScalingPolicyExists(n string, policy *autoscaling.ScalingPolicy) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[n] | ||
|
@@ -375,3 +415,79 @@ resource "aws_autoscaling_policy" "foobar_simple" { | |
} | ||
`, name, name, name) | ||
} | ||
|
||
func testAccAwsAutoscalingPolicyConfig_TargetTracking_Predefined(rName string) string { | ||
return fmt.Sprintf(` | ||
resource "aws_launch_configuration" "test" { | ||
name = "tf-test-%s" | ||
image_id = "ami-21f78e11" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: Do you mind using the AMI data source here instead, so we don't need to keep updating the ID over time as often? |
||
instance_type = "t1.micro" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK |
||
} | ||
|
||
resource "aws_autoscaling_group" "test" { | ||
availability_zones = ["us-west-2a"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mind using the AZ data source here to make the test region-agnostic? |
||
name = "tf-test-%s" | ||
max_size = 5 | ||
min_size = 0 | ||
health_check_grace_period = 300 | ||
health_check_type = "ELB" | ||
force_delete = true | ||
termination_policies = ["OldestInstance"] | ||
launch_configuration = "${aws_launch_configuration.test.name}" | ||
} | ||
|
||
resource "aws_autoscaling_policy" "test" { | ||
name = "tf-as-%s" | ||
policy_type = "TargetTrackingScaling" | ||
autoscaling_group_name = "${aws_autoscaling_group.test.name}" | ||
|
||
target_tracking_configuration { | ||
predefined_metric_specification { | ||
predefined_metric_type = "ASGAverageCPUUtilization" | ||
} | ||
target_value = 40.0 | ||
} | ||
} | ||
`, rName, rName, rName) | ||
} | ||
|
||
func testAccAwsAutoscalingPolicyConfig_TargetTracking_Custom(rName string) string { | ||
return fmt.Sprintf(` | ||
resource "aws_launch_configuration" "test" { | ||
name = "tf-test-%s" | ||
image_id = "ami-21f78e11" | ||
instance_type = "t1.micro" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise - as above ^ |
||
} | ||
|
||
resource "aws_autoscaling_group" "test" { | ||
availability_zones = ["us-west-2a"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise - as above ^ |
||
name = "tf-test-%s" | ||
max_size = 5 | ||
min_size = 0 | ||
health_check_grace_period = 300 | ||
health_check_type = "ELB" | ||
force_delete = true | ||
termination_policies = ["OldestInstance"] | ||
launch_configuration = "${aws_launch_configuration.test.name}" | ||
} | ||
|
||
resource "aws_autoscaling_policy" "test" { | ||
name = "tf-as-%s" | ||
policy_type = "TargetTrackingScaling" | ||
autoscaling_group_name = "${aws_autoscaling_group.test.name}" | ||
|
||
target_tracking_configuration { | ||
customized_metric_specification { | ||
metric_dimension { | ||
name = "fuga" | ||
value = "fuga" | ||
} | ||
metric_name = "hoge" | ||
namespace = "hoge" | ||
statistic = "Average" | ||
} | ||
target_value = 40.0 | ||
} | ||
} | ||
`, rName, rName, rName) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like
target_tracking_configuration
is a singleton - i.e. we'll only ever have a single instance of it since it maps to a struct, not a map nor a slice. Do you mind changing it toschema.TypeList
and attachingMaxItems: 1
? We generally prefer TypeList for singletons because it's much easier to work with the field without the hash and because there's really no ordering problem as there's nothing to order, so no reason for set.