Skip to content
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

r/aws_autoscaling_lifecycle_hook: Add plan time validation for aws_autoscaling_lifecycle_hook #12145

Merged
7 changes: 7 additions & 0 deletions .changelog/12145.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_autoscaling_group: Add plan-time validation of `initial_lifecycle_hook.default_result`, `initial_lifecycle_hook.heartbeat_timeout`, `initial_lifecycle_hook.lifecycle_transition`, `initial_lifecycle_hook.name`, `initial_lifecycle_hook.notification_target_arn` and `initial_lifecycle_hook.role_arn`
```

```release-note:enhancement
resource/aws_autoscaling_lifecycle_hook: Add plan-time validation of `default_result`, `heartbeat_timeout`, `lifecycle_transition`, `name`, `notification_target_arn` and `role_arn`
```
24 changes: 24 additions & 0 deletions internal/service/autoscaling/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,27 @@ const (
const (
launchTemplateIDUnknown = "unknown"
)

const (
lifecycleHookDefaultResultAbandon = "ABANDON"
lifecycleHookDefaultResultContinue = "CONTINUE"
)

func lifecycleHookDefaultResult_Values() []string {
return []string{
lifecycleHookDefaultResultAbandon,
lifecycleHookDefaultResultContinue,
}
}

const (
lifecycleHookLifecycleTransitionInstanceLaunching = "autoscaling:EC2_INSTANCE_LAUNCHING"
lifecycleHookLifecycleTransitionInstanceTerminating = "autoscaling:EC2_INSTANCE_TERMINATING"
)

func lifecycleHookLifecycleTransition_Values() []string {
return []string{
lifecycleHookLifecycleTransitionInstanceLaunching,
lifecycleHookLifecycleTransitionInstanceTerminating,
}
}
42 changes: 26 additions & 16 deletions internal/service/autoscaling/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,40 +138,50 @@ func ResourceGroup() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"default_result": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(lifecycleHookDefaultResult_Values(), false),
},
"heartbeat_timeout": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
ValidateFunc: validation.IntBetween(30, 7200),
},
"lifecycle_transition": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(lifecycleHookLifecycleTransition_Values(), false),
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.All(
validation.StringLenBetween(1, 255),
validation.StringMatch(regexache.MustCompile(`[A-Za-z0-9\-_\/]+`),
`no spaces or special characters except "-", "_", and "/"`),
),
},
"notification_metadata": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"notification_target_arn": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: verify.ValidARN,
},
"role_arn": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: verify.ValidARN,
},
},
},
Expand Down
100 changes: 53 additions & 47 deletions internal/service/autoscaling/lifecycle_hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ import (
"strings"
"time"

"github.com/YakDriver/regexache"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

// @SDKResource("aws_autoscaling_lifecycle_hook")
Expand All @@ -39,34 +42,44 @@ func ResourceLifecycleHook() *schema.Resource {
Required: true,
},
"default_result": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice(lifecycleHookDefaultResult_Values(), false),
},
"heartbeat_timeout": {
Type: schema.TypeInt,
Optional: true,
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(30, 7200),
},
"lifecycle_transition": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(lifecycleHookLifecycleTransition_Values(), false),
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.All(
validation.StringLenBetween(1, 255),
validation.StringMatch(regexache.MustCompile(`[A-Za-z0-9\-_\/]+`),
`no spaces or special characters except "-", "_", and "/"`),
),
},
"notification_metadata": {
Type: schema.TypeString,
Optional: true,
},
"notification_target_arn": {
Type: schema.TypeString,
Optional: true,
Type: schema.TypeString,
Optional: true,
ValidateFunc: verify.ValidARN,
},
"role_arn": {
Type: schema.TypeString,
Optional: true,
Type: schema.TypeString,
Optional: true,
ValidateFunc: verify.ValidARN,
},
},
}
Expand All @@ -76,10 +89,36 @@ func resourceLifecycleHookPut(ctx context.Context, d *schema.ResourceData, meta
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).AutoScalingConn(ctx)

input := getPutLifecycleHookInput(d)
name := d.Get("name").(string)
input := &autoscaling.PutLifecycleHookInput{
AutoScalingGroupName: aws.String(d.Get("autoscaling_group_name").(string)),
LifecycleHookName: aws.String(name),
}

if v, ok := d.GetOk("default_result"); ok {
input.DefaultResult = aws.String(v.(string))
}

if v, ok := d.GetOk("heartbeat_timeout"); ok {
input.HeartbeatTimeout = aws.Int64(int64(v.(int)))
}

if v, ok := d.GetOk("lifecycle_transition"); ok {
input.LifecycleTransition = aws.String(v.(string))
}

if v, ok := d.GetOk("notification_metadata"); ok {
input.NotificationMetadata = aws.String(v.(string))
}

if v, ok := d.GetOk("notification_target_arn"); ok {
input.NotificationTargetARN = aws.String(v.(string))
}

if v, ok := d.GetOk("role_arn"); ok {
input.RoleARN = aws.String(v.(string))
}

log.Printf("[INFO] Putting Auto Scaling Lifecycle Hook: %s", input)
_, err := tfresource.RetryWhenAWSErrMessageContains(ctx, 5*time.Minute,
func() (interface{}, error) {
return conn.PutLifecycleHookWithContext(ctx, input)
Expand Down Expand Up @@ -114,9 +153,9 @@ func resourceLifecycleHookRead(ctx context.Context, d *schema.ResourceData, meta
d.Set("default_result", p.DefaultResult)
d.Set("heartbeat_timeout", p.HeartbeatTimeout)
d.Set("lifecycle_transition", p.LifecycleTransition)
d.Set("name", p.LifecycleHookName)
d.Set("notification_metadata", p.NotificationMetadata)
d.Set("notification_target_arn", p.NotificationTargetARN)
d.Set("name", p.LifecycleHookName)
d.Set("role_arn", p.RoleARN)

return diags
Expand All @@ -143,39 +182,6 @@ func resourceLifecycleHookDelete(ctx context.Context, d *schema.ResourceData, me
return diags
}

func getPutLifecycleHookInput(d *schema.ResourceData) *autoscaling.PutLifecycleHookInput {
var params = &autoscaling.PutLifecycleHookInput{
AutoScalingGroupName: aws.String(d.Get("autoscaling_group_name").(string)),
LifecycleHookName: aws.String(d.Get("name").(string)),
}

if v, ok := d.GetOk("default_result"); ok {
params.DefaultResult = aws.String(v.(string))
}

if v, ok := d.GetOk("heartbeat_timeout"); ok {
params.HeartbeatTimeout = aws.Int64(int64(v.(int)))
}

if v, ok := d.GetOk("lifecycle_transition"); ok {
params.LifecycleTransition = aws.String(v.(string))
}

if v, ok := d.GetOk("notification_metadata"); ok {
params.NotificationMetadata = aws.String(v.(string))
}

if v, ok := d.GetOk("notification_target_arn"); ok {
params.NotificationTargetARN = aws.String(v.(string))
}

if v, ok := d.GetOk("role_arn"); ok {
params.RoleARN = aws.String(v.(string))
}

return params
}

func FindLifecycleHook(ctx context.Context, conn *autoscaling.AutoScaling, asgName, hookName string) (*autoscaling.LifecycleHook, error) {
input := &autoscaling.DescribeLifecycleHooksInput{
AutoScalingGroupName: aws.String(asgName),
Expand Down