diff --git a/.changelog/35671.txt b/.changelog/35671.txt new file mode 100644 index 00000000000..7c9da01c624 --- /dev/null +++ b/.changelog/35671.txt @@ -0,0 +1,15 @@ +```release-note:bug +resource/aws_lb_listener: Was not storing `default_action[].forward` in state if only a single `target_group` was set. +``` + +```release-note:bug +resource/aws_lb_listener_rule: Was not storing `action[].forward` in state if only a single `target_group` was set. +``` + +```release-note:bug +resource/aws_lb_listener: Was incorrectly reporting conflicting `default_action[].target_group_arn` when `ignore_changes` was set. +``` + +```release-note:bug +resource/aws_lb_listener_rule: Was incorrectly reporting conflicting `action[].target_group_arn` when `ignore_changes` was set. +``` diff --git a/internal/service/elbv2/listener.go b/internal/service/elbv2/listener.go index dd0eaddc435..159d62abf77 100644 --- a/internal/service/elbv2/listener.go +++ b/internal/service/elbv2/listener.go @@ -214,9 +214,11 @@ func ResourceListener() *schema.Resource { }, }, "forward": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + DiffSuppressOnRefresh: true, + DiffSuppressFunc: diffSuppressMissingForward("default_action"), + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "target_group": { @@ -511,7 +513,7 @@ func resourceListenerRead(ctx context.Context, d *schema.ResourceData, meta inte sort.Slice(listener.DefaultActions, func(i, j int) bool { return aws.ToInt32(listener.DefaultActions[i].Order) < aws.ToInt32(listener.DefaultActions[j].Order) }) - if err := d.Set("default_action", flattenLbListenerActions(d, listener.DefaultActions)); err != nil { + if err := d.Set("default_action", flattenLbListenerActions(d, "default_action", listener.DefaultActions)); err != nil { return sdkdiag.AppendErrorf(diags, "setting default_action: %s", err) } d.Set("load_balancer_arn", listener.LoadBalancerArn) @@ -928,20 +930,26 @@ func expandLbListenerActionForwardConfigTargetGroupStickinessConfig(l []interfac return nil } + // The Plugin SDK stores a `nil` returned by the API as a `0` in the state. This is a invalid value. + var duration *int32 + if v := tfMap["duration"].(int); v > 0 { + duration = aws.Int32(int32(v)) + } + return &awstypes.TargetGroupStickinessConfig{ Enabled: aws.Bool(tfMap["enabled"].(bool)), - DurationSeconds: aws.Int32(int32(tfMap["duration"].(int))), + DurationSeconds: duration, } } -func flattenLbListenerActions(d *schema.ResourceData, Actions []awstypes.Action) []interface{} { - if len(Actions) == 0 { +func flattenLbListenerActions(d *schema.ResourceData, attrName string, actions []awstypes.Action) []interface{} { + if len(actions) == 0 { return []interface{}{} } var vActions []interface{} - for i, action := range Actions { + for i, action := range actions { m := map[string]interface{}{ "type": string(action.Type), "order": aws.ToInt32(action.Order), @@ -949,11 +957,7 @@ func flattenLbListenerActions(d *schema.ResourceData, Actions []awstypes.Action) switch action.Type { case awstypes.ActionTypeEnumForward: - if aws.ToString(action.TargetGroupArn) != "" { - m["target_group_arn"] = aws.ToString(action.TargetGroupArn) - } else { - m["forward"] = flattenLbListenerActionForwardConfig(action.ForwardConfig) - } + flattenLbForwardAction(d, attrName, i, action, m) case awstypes.ActionTypeEnumRedirect: m["redirect"] = flattenLbListenerActionRedirectConfig(action.RedirectConfig) @@ -968,7 +972,7 @@ func flattenLbListenerActions(d *schema.ResourceData, Actions []awstypes.Action) // The LB API currently provides no way to read the ClientSecret // Instead we passthrough the configuration value into the state var clientSecret string - if v, ok := d.GetOk("default_action." + strconv.Itoa(i) + ".authenticate_oidc.0.client_secret"); ok { + if v, ok := d.GetOk(attrName + "." + strconv.Itoa(i) + ".authenticate_oidc.0.client_secret"); ok { clientSecret = v.(string) } @@ -981,6 +985,50 @@ func flattenLbListenerActions(d *schema.ResourceData, Actions []awstypes.Action) return vActions } +func flattenLbForwardAction(d *schema.ResourceData, attrName string, i int, awsAction awstypes.Action, actionMap map[string]any) { + // On create and update, we have a Config + // On refresh, we have a populated State + // On import, we have an empty State and empty Config + + if rawConfig := d.GetRawConfig(); rawConfig.IsKnown() && !rawConfig.IsNull() { + actions := rawConfig.GetAttr(attrName) + flattenLbForwardActionOneOf(actions, i, awsAction, actionMap) + return + } + + rawState := d.GetRawState() + defaultActions := rawState.GetAttr(attrName) + + if defaultActions.LengthInt() > 0 { + flattenLbForwardActionOneOf(defaultActions, i, awsAction, actionMap) + return + } + + flattenLbForwardActionBoth(awsAction, actionMap) +} + +func flattenLbForwardActionOneOf(actions cty.Value, i int, awsAction awstypes.Action, actionMap map[string]any) { + if actions.IsKnown() && !actions.IsNull() { + index := cty.NumberIntVal(int64(i)) + if actions.HasIndex(index).True() { + action := actions.Index(index) + if action.IsKnown() && !action.IsNull() { + forward := action.GetAttr("forward") + if forward.IsKnown() && forward.LengthInt() > 0 { + actionMap["forward"] = flattenLbListenerActionForwardConfig(awsAction.ForwardConfig) + } else { + actionMap["target_group_arn"] = aws.ToString(awsAction.TargetGroupArn) + } + } + } + } +} + +func flattenLbForwardActionBoth(awsAction awstypes.Action, actionMap map[string]any) { + actionMap["target_group_arn"] = aws.ToString(awsAction.TargetGroupArn) + actionMap["forward"] = flattenLbListenerActionForwardConfig(awsAction.ForwardConfig) +} + func flattenMutualAuthenticationAttributes(description *awstypes.MutualAuthenticationAttributes) []interface{} { if description == nil { return []interface{}{} @@ -1195,7 +1243,8 @@ func listenerActionPlantimeValidate(actionPath cty.Path, action cty.Value, diags tga := action.GetAttr("target_group_arn") f := action.GetAttr("forward") - if !tga.IsNull() && (!f.IsNull() && f.LengthInt() > 0) { + // If `ignore_changes` is set, even if there is no value in the configuration, the value in RawConfig is "" on refresh. + if (tga.IsKnown() && !tga.IsNull() && tga.AsString() != "") && (f.IsKnown() && !f.IsNull() && f.LengthInt() > 0) { *diags = append(*diags, errs.NewAttributeErrorDiagnostic(actionPath, "Invalid Attribute Combination", fmt.Sprintf("Only one of %q or %q can be specified.", @@ -1321,3 +1370,15 @@ func listenerActionRuntimeValidate(actionPath cty.Path, action map[string]any, d } } } + +func diffSuppressMissingForward(attrName string) schema.SchemaDiffSuppressFunc { + return func(k, old, new string, d *schema.ResourceData) bool { + if regexache.MustCompile(fmt.Sprintf(`^%s\.\d+\.forward\.#$`, attrName)).MatchString(k) { + return old == "1" && new == "0" + } + if regexache.MustCompile(fmt.Sprintf(`^%s\.\d+\.forward\.\d+\.target_group\.#$`, attrName)).MatchString(k) { + return old == "1" && new == "0" + } + return false + } +} diff --git a/internal/service/elbv2/listener_certificate_test.go b/internal/service/elbv2/listener_certificate_test.go index c9dbc7909d2..78cdb728257 100644 --- a/internal/service/elbv2/listener_certificate_test.go +++ b/internal/service/elbv2/listener_certificate_test.go @@ -9,14 +9,15 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" + awstypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tfelbv2 "github.com/hashicorp/terraform-provider-aws/internal/service/elbv2" ) @@ -211,21 +212,21 @@ func TestAccELBV2ListenerCertificate_disappears_Listener(t *testing.T) { func testAccCheckListenerCertificateDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_lb_listener_certificate" { continue } - input := &elbv2.DescribeListenerCertificatesInput{ + input := &elasticloadbalancingv2.DescribeListenerCertificatesInput{ ListenerArn: aws.String(rs.Primary.Attributes["listener_arn"]), - PageSize: aws.Int64(400), + PageSize: aws.Int32(400), } - resp, err := conn.DescribeListenerCertificatesWithContext(ctx, input) + resp, err := conn.DescribeListenerCertificates(ctx, input) if err != nil { - if tfawserr.ErrCodeEquals(err, elbv2.ErrCodeListenerNotFoundException) { + if errs.IsA[*awstypes.ListenerNotFoundException](err) { return nil } return err @@ -233,11 +234,11 @@ func testAccCheckListenerCertificateDestroy(ctx context.Context) resource.TestCh for _, cert := range resp.Certificates { // We only care about additional certificates. - if aws.BoolValue(cert.IsDefault) { + if aws.ToBool(cert.IsDefault) { continue } - if aws.StringValue(cert.CertificateArn) == rs.Primary.Attributes["certificate_arn"] { + if aws.ToString(cert.CertificateArn) == rs.Primary.Attributes["certificate_arn"] { return errors.New("LB listener certificate not destroyed") } } diff --git a/internal/service/elbv2/listener_data_source.go b/internal/service/elbv2/listener_data_source.go index c9ec31a2665..a209c9338b5 100644 --- a/internal/service/elbv2/listener_data_source.go +++ b/internal/service/elbv2/listener_data_source.go @@ -338,7 +338,7 @@ func dataSourceListenerRead(ctx context.Context, d *schema.ResourceData, meta in sort.Slice(listener.DefaultActions, func(i, j int) bool { return aws.ToInt32(listener.DefaultActions[i].Order) < aws.ToInt32(listener.DefaultActions[j].Order) }) - if err := d.Set("default_action", flattenLbListenerActions(d, listener.DefaultActions)); err != nil { + if err := d.Set("default_action", flattenLbListenerActions(d, "default_action", listener.DefaultActions)); err != nil { return sdkdiag.AppendErrorf(diags, "setting default_action: %s", err) } d.Set("load_balancer_arn", listener.LoadBalancerArn) diff --git a/internal/service/elbv2/listener_rule.go b/internal/service/elbv2/listener_rule.go index 6da74fd1239..047ee68dee7 100644 --- a/internal/service/elbv2/listener_rule.go +++ b/internal/service/elbv2/listener_rule.go @@ -98,9 +98,11 @@ func ResourceListenerRule() *schema.Resource { }, "forward": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + DiffSuppressOnRefresh: true, + DiffSuppressFunc: diffSuppressMissingForward("action"), + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "target_group": { @@ -591,41 +593,9 @@ func resourceListenerRuleRead(ctx context.Context, d *schema.ResourceData, meta sort.Slice(rule.Actions, func(i, j int) bool { return aws.ToInt32(rule.Actions[i].Order) < aws.ToInt32(rule.Actions[j].Order) }) - actions := make([]interface{}, len(rule.Actions)) - for i, action := range rule.Actions { - actionMap := map[string]interface{}{ - "type": string(action.Type), - "order": aws.ToInt32(action.Order), - } - - switch action.Type { - case awstypes.ActionTypeEnumForward: - if aws.ToString(action.TargetGroupArn) != "" { - actionMap["target_group_arn"] = aws.ToString(action.TargetGroupArn) - } else { - actionMap["forward"] = flattenLbListenerActionForwardConfig(action.ForwardConfig) - } - - case awstypes.ActionTypeEnumRedirect: - actionMap["redirect"] = flattenLbListenerActionRedirectConfig(action.RedirectConfig) - - case awstypes.ActionTypeEnumFixedResponse: - actionMap["fixed_response"] = flattenLbListenerActionFixedResponseConfig(action.FixedResponseConfig) - - case awstypes.ActionTypeEnumAuthenticateCognito: - actionMap["authenticate_cognito"] = flattenLbListenerActionAuthenticateCognitoConfig(action.AuthenticateCognitoConfig) - - case awstypes.ActionTypeEnumAuthenticateOidc: - // The LB API currently provides no way to read the ClientSecret - // Instead we passthrough the configuration value into the state - clientSecret := d.Get("action." + strconv.Itoa(i) + ".authenticate_oidc.0.client_secret").(string) - - actionMap["authenticate_oidc"] = flattenAuthenticateOIDCActionConfig(action.AuthenticateOidcConfig, clientSecret) - } - - actions[i] = actionMap + if err := d.Set("action", flattenLbListenerActions(d, "action", rule.Actions)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting action: %s", err) } - d.Set("action", actions) conditions := make([]interface{}, len(rule.Conditions)) for i, condition := range rule.Conditions { diff --git a/internal/service/elbv2/listener_rule_test.go b/internal/service/elbv2/listener_rule_test.go index c5690cb813a..f28fc7c62ca 100644 --- a/internal/service/elbv2/listener_rule_test.go +++ b/internal/service/elbv2/listener_rule_test.go @@ -12,15 +12,15 @@ import ( "testing" "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" awstypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tfelbv2 "github.com/hashicorp/terraform-provider-aws/internal/service/elbv2" "golang.org/x/exp/slices" ) @@ -70,7 +70,7 @@ func TestLBListenerARNFromRuleARN(t *testing.T) { func TestAccELBV2ListenerRule_basic(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lb_listener_rule.test" listenerResourceName := "aws_lb_listener.test" @@ -117,7 +117,7 @@ func TestAccELBV2ListenerRule_basic(t *testing.T) { func TestAccELBV2ListenerRule_disappears(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lb_listener_rule.test" @@ -141,7 +141,7 @@ func TestAccELBV2ListenerRule_disappears(t *testing.T) { func TestAccELBV2ListenerRule_tags(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lb_listener_rule.test" @@ -180,9 +180,62 @@ func TestAccELBV2ListenerRule_tags(t *testing.T) { }) } +func TestAccELBV2ListenerRule_updateForwardBasic(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName = rName[:30] + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_forwardBasic(rName, "test1"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.target_group_arn", "aws_lb_target_group.test1", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.forward", + }, + }, + { + Config: testAccListenerRuleConfig_forwardBasic(rName, "test2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.target_group_arn", "aws_lb_target_group.test2", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.forward", + }, + }, + }, + }) +} + func TestAccELBV2ListenerRule_forwardWeighted(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-weighted-%s", sdkacctest.RandString(13)) targetGroupName1 := fmt.Sprintf("testtargetgroup-%s", sdkacctest.RandString(10)) targetGroupName2 := fmt.Sprintf("testtargetgroup-%s", sdkacctest.RandString(10)) @@ -269,7 +322,7 @@ func TestAccELBV2ListenerRule_forwardTargetARNAndBlock(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckListenerDestroy(ctx), + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccListenerRuleConfig_forwardTargetARNAndBlock(rName), @@ -279,10 +332,557 @@ func TestAccELBV2ListenerRule_forwardTargetARNAndBlock(t *testing.T) { }) } +func TestAccELBV2ListenerRule_ActionForward_TargetGroupARNToForwardBlock_NoChanges(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_TargetGroupARN(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.forward", + }, + }, + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockBasic(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRule_ActionForward_ForwardBlock_AddStickiness(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockBasic(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockStickiness(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "3600"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRule_ActionForward_ForwardBlock_RemoveStickiness(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockStickiness(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "3600"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockBasic(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRule_ActionForward_TargetGroupARNToForwardBlock_WeightAndStickiness(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_TargetGroupARN(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.forward", + }, + }, + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockWeightAndStickiness(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "3600"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRule_ActionForward_ForwardBlockToTargetGroupARN_NoChanges(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockBasic(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + { + Config: testAccListenerRuleConfig_actionForward_TargetGroupARN(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.forward", + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRule_ActionForward_ForwardBlockToTargetGroupARN_WeightAndStickiness(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockWeightAndStickiness(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "3600"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + { + Config: testAccListenerRuleConfig_actionForward_TargetGroupARN(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.forward", + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRule_ActionForward_ForwardBlock_AddAction(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockBasic(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockAddAction(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "authenticate-oidc"), + resource.TestCheckResourceAttr(resourceName, "action.1.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.1.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.1.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.authenticate_oidc.0.client_secret", + "action.1.target_group_arn", + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRule_ActionForward_ForwardBlock_RemoveAction(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockAddAction(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "authenticate-oidc"), + resource.TestCheckResourceAttr(resourceName, "action.1.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.1.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.1.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.1.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.authenticate_oidc.0.client_secret", + "action.1.target_group_arn", + }, + }, + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockBasic(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.target_group_arn", + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRule_ActionForward_IgnoreFields(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + resourceName := "aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName = rName[:30] + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_actionForward_ForwardBlockMultiTargetWithIgnore(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.target_group.#", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.redirect.#", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + // TestAccELBV2ListenerRule_backwardsCompatibility confirms that the resource type `aws_alb_listener_rule` works func TestAccELBV2ListenerRule_backwardsCompatibility(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-basic-%s", sdkacctest.RandString(13)) targetGroupName := fmt.Sprintf("testtargetgroup-%s", sdkacctest.RandString(10)) @@ -330,7 +930,7 @@ func TestAccELBV2ListenerRule_backwardsCompatibility(t *testing.T) { func TestAccELBV2ListenerRule_redirect(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-redirect-%s", sdkacctest.RandString(14)) resourceName := "aws_lb_listener_rule.static" @@ -420,7 +1020,7 @@ func TestAccELBV2ListenerRule_redirect(t *testing.T) { func TestAccELBV2ListenerRule_fixedResponse(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-fixedresponse-%s", sdkacctest.RandString(9)) resourceName := "aws_lb_listener_rule.static" @@ -460,7 +1060,7 @@ func TestAccELBV2ListenerRule_fixedResponse(t *testing.T) { // Updating Action breaks Condition change logic GH-11323 and GH-11362 func TestAccELBV2ListenerRule_updateFixedResponse(t *testing.T) { ctx := acctest.Context(t) - var rule elbv2.Rule + var rule awstypes.Rule lbName := fmt.Sprintf("testrule-basic-%s", sdkacctest.RandString(13)) resourceName := "aws_lb_listener_rule.static" @@ -491,7 +1091,7 @@ func TestAccELBV2ListenerRule_updateFixedResponse(t *testing.T) { func TestAccELBV2ListenerRule_updateRulePriority(t *testing.T) { ctx := acctest.Context(t) - var before, after elbv2.Rule + var before, after awstypes.Rule rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lb_listener_rule.test" @@ -522,7 +1122,7 @@ func TestAccELBV2ListenerRule_updateRulePriority(t *testing.T) { func TestAccELBV2ListenerRule_changeListenerRuleARNForcesNew(t *testing.T) { ctx := acctest.Context(t) - var before, after elbv2.Rule + var before, after awstypes.Rule rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lb_listener_rule.test" @@ -551,7 +1151,7 @@ func TestAccELBV2ListenerRule_changeListenerRuleARNForcesNew(t *testing.T) { func TestAccELBV2ListenerRule_priority(t *testing.T) { ctx := acctest.Context(t) - var rule elbv2.Rule + var rule awstypes.Rule rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) if testing.Short() { @@ -569,29 +1169,37 @@ func TestAccELBV2ListenerRule_priority(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckListenerRuleExists(ctx, "aws_lb_listener_rule.first", &rule), resource.TestCheckResourceAttr("aws_lb_listener_rule.first", "priority", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.third", "priority", "3"), ), }, { - Config: testAccListenerRuleConfig_priorityLast(rName), + Config: testAccListenerRuleConfig_priorityLastNoPriority(rName), Check: resource.ComposeTestCheckFunc( testAccCheckListenerRuleExists(ctx, "aws_lb_listener_rule.last", &rule), resource.TestCheckResourceAttr("aws_lb_listener_rule.last", "priority", "4"), ), }, { - Config: testAccListenerRuleConfig_priorityStatic(rName), + Config: testAccListenerRuleConfig_priorityLastSpecifyPriority(rName, "7"), Check: resource.ComposeTestCheckFunc( testAccCheckListenerRuleExists(ctx, "aws_lb_listener_rule.last", &rule), resource.TestCheckResourceAttr("aws_lb_listener_rule.last", "priority", "7"), ), }, { - Config: testAccListenerRuleConfig_priorityLast(rName), + Config: testAccListenerRuleConfig_priorityLastNoPriority(rName), Check: resource.ComposeTestCheckFunc( testAccCheckListenerRuleExists(ctx, "aws_lb_listener_rule.last", &rule), resource.TestCheckResourceAttr("aws_lb_listener_rule.last", "priority", "7"), ), }, + { + Config: testAccListenerRuleConfig_priorityLastSpecifyPriority(rName, "6"), + Check: resource.ComposeTestCheckFunc( + testAccCheckListenerRuleExists(ctx, "aws_lb_listener_rule.last", &rule), + resource.TestCheckResourceAttr("aws_lb_listener_rule.last", "priority", "6"), + ), + }, { Config: testAccListenerRuleConfig_priorityParallelism(rName), Check: resource.ComposeTestCheckFunc( @@ -638,7 +1246,7 @@ func TestAccELBV2ListenerRule_priority(t *testing.T) { func TestAccELBV2ListenerRule_cognito(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -682,7 +1290,7 @@ func TestAccELBV2ListenerRule_cognito(t *testing.T) { func TestAccELBV2ListenerRule_oidc(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -726,7 +1334,7 @@ func TestAccELBV2ListenerRule_oidc(t *testing.T) { func TestAccELBV2ListenerRule_Action_defaultOrder(t *testing.T) { ctx := acctest.Context(t) - var rule elbv2.Rule + var rule awstypes.Rule key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -748,10 +1356,13 @@ func TestAccELBV2ListenerRule_Action_defaultOrder(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"action.0.authenticate_oidc.0.client_secret"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.authenticate_oidc.0.client_secret", + "action.1.forward", + }, }, }, }) @@ -759,7 +1370,7 @@ func TestAccELBV2ListenerRule_Action_defaultOrder(t *testing.T) { func TestAccELBV2ListenerRule_Action_specifyOrder(t *testing.T) { ctx := acctest.Context(t) - var rule elbv2.Rule + var rule awstypes.Rule key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -781,10 +1392,13 @@ func TestAccELBV2ListenerRule_Action_specifyOrder(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"action.0.authenticate_oidc.0.client_secret"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "action.0.authenticate_oidc.0.client_secret", + "action.1.forward", + }, }, }, }) @@ -793,7 +1407,7 @@ func TestAccELBV2ListenerRule_Action_specifyOrder(t *testing.T) { // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/6171 func TestAccELBV2ListenerRule_Action_actionDisappears(t *testing.T) { ctx := acctest.Context(t) - var rule elbv2.Rule + var rule awstypes.Rule key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -884,7 +1498,7 @@ func TestAccELBV2ListenerRule_EmptyAction(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckListenerDestroy(ctx), + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccListenerRuleConfig_EmptyAction(rName, testcase.actionType), @@ -932,7 +1546,7 @@ func TestAccELBV2ListenerRule_conditionAttributesCount(t *testing.T) { func TestAccELBV2ListenerRule_conditionHostHeader(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-hostHeader-%s", sdkacctest.RandString(12)) resourceName := "aws_lb_listener_rule.static" @@ -972,7 +1586,7 @@ func TestAccELBV2ListenerRule_conditionHostHeader(t *testing.T) { func TestAccELBV2ListenerRule_conditionHTTPHeader(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-httpHeader-%s", sdkacctest.RandString(12)) resourceName := "aws_lb_listener_rule.static" @@ -1040,7 +1654,7 @@ func TestAccELBV2ListenerRule_ConditionHTTPHeader_invalid(t *testing.T) { func TestAccELBV2ListenerRule_conditionHTTPRequestMethod(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-httpRequest-%s", sdkacctest.RandString(11)) resourceName := "aws_lb_listener_rule.static" @@ -1080,7 +1694,7 @@ func TestAccELBV2ListenerRule_conditionHTTPRequestMethod(t *testing.T) { func TestAccELBV2ListenerRule_conditionPathPattern(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-pathPattern-%s", sdkacctest.RandString(11)) resourceName := "aws_lb_listener_rule.static" @@ -1120,7 +1734,7 @@ func TestAccELBV2ListenerRule_conditionPathPattern(t *testing.T) { func TestAccELBV2ListenerRule_conditionQueryString(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-queryString-%s", sdkacctest.RandString(11)) resourceName := "aws_lb_listener_rule.static" @@ -1184,7 +1798,7 @@ func TestAccELBV2ListenerRule_conditionQueryString(t *testing.T) { func TestAccELBV2ListenerRule_conditionSourceIP(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-sourceIp-%s", sdkacctest.RandString(14)) resourceName := "aws_lb_listener_rule.static" @@ -1224,7 +1838,7 @@ func TestAccELBV2ListenerRule_conditionSourceIP(t *testing.T) { func TestAccELBV2ListenerRule_conditionUpdateMixed(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-mixed-%s", sdkacctest.RandString(17)) resourceName := "aws_lb_listener_rule.static" @@ -1303,7 +1917,7 @@ func TestAccELBV2ListenerRule_conditionUpdateMixed(t *testing.T) { func TestAccELBV2ListenerRule_conditionMultiple(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-condMulti-%s", sdkacctest.RandString(13)) resourceName := "aws_lb_listener_rule.static" @@ -1387,7 +2001,7 @@ func TestAccELBV2ListenerRule_conditionMultiple(t *testing.T) { func TestAccELBV2ListenerRule_conditionUpdateMultiple(t *testing.T) { ctx := acctest.Context(t) - var conf elbv2.Rule + var conf awstypes.Rule lbName := fmt.Sprintf("testrule-condMulti-%s", sdkacctest.RandString(13)) resourceName := "aws_lb_listener_rule.static" @@ -1483,12 +2097,12 @@ func TestAccELBV2ListenerRule_conditionUpdateMultiple(t *testing.T) { }) } -func testAccCheckListenerRuleActionOrderDisappears(ctx context.Context, rule *elbv2.Rule, actionOrderToDelete int) resource.TestCheckFunc { +func testAccCheckListenerRuleActionOrderDisappears(ctx context.Context, rule *awstypes.Rule, actionOrderToDelete int) resource.TestCheckFunc { return func(s *terraform.State) error { - var newActions []*elbv2.Action + var newActions []awstypes.Action for i, action := range rule.Actions { - if int(aws.Int64Value(action.Order)) == actionOrderToDelete { + if int(aws.ToInt32(action.Order)) == actionOrderToDelete { newActions = slices.Delete(rule.Actions, i, i+1) break } @@ -1498,22 +2112,22 @@ func testAccCheckListenerRuleActionOrderDisappears(ctx context.Context, rule *el return fmt.Errorf("Unable to find action order %d from actions: %#v", actionOrderToDelete, rule.Actions) } - conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) - input := &elbv2.ModifyRuleInput{ + input := &elasticloadbalancingv2.ModifyRuleInput{ Actions: newActions, RuleArn: rule.RuleArn, } - _, err := conn.ModifyRuleWithContext(ctx, input) + _, err := conn.ModifyRule(ctx, input) return err } } -func testAccCheckListenerRuleNotRecreated(t *testing.T, before, after *elbv2.Rule) resource.TestCheckFunc { +func testAccCheckListenerRuleNotRecreated(t *testing.T, before, after *awstypes.Rule) resource.TestCheckFunc { return func(s *terraform.State) error { - if before, after := aws.StringValue(before.RuleArn), aws.StringValue(after.RuleArn); before != after { + if before, after := aws.ToString(before.RuleArn), aws.ToString(after.RuleArn); before != after { t.Fatalf("ELBv2 Listener Rule (%s) was recreated: %s", before, after) } @@ -1521,9 +2135,9 @@ func testAccCheckListenerRuleNotRecreated(t *testing.T, before, after *elbv2.Rul } } -func testAccCheckListenerRuleRecreated(t *testing.T, before, after *elbv2.Rule) resource.TestCheckFunc { +func testAccCheckListenerRuleRecreated(t *testing.T, before, after *awstypes.Rule) resource.TestCheckFunc { return func(s *terraform.State) error { - if before, after := aws.StringValue(before.RuleArn), aws.StringValue(after.RuleArn); before == after { + if before, after := aws.ToString(before.RuleArn), aws.ToString(after.RuleArn); before == after { t.Fatalf("ELBv2 Listener Rule (%s) was not recreated", before) } @@ -1531,7 +2145,7 @@ func testAccCheckListenerRuleRecreated(t *testing.T, before, after *elbv2.Rule) } } -func testAccCheckListenerRuleExists(ctx context.Context, n string, res *elbv2.Rule) resource.TestCheckFunc { +func testAccCheckListenerRuleExists(ctx context.Context, n string, res *awstypes.Rule) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -1542,10 +2156,10 @@ func testAccCheckListenerRuleExists(ctx context.Context, n string, res *elbv2.Ru return errors.New("No Listener Rule ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) - describe, err := conn.DescribeRulesWithContext(ctx, &elbv2.DescribeRulesInput{ - RuleArns: []*string{aws.String(rs.Primary.ID)}, + describe, err := conn.DescribeRules(ctx, &elasticloadbalancingv2.DescribeRulesInput{ + RuleArns: []string{rs.Primary.ID}, }) if err != nil { @@ -1557,22 +2171,22 @@ func testAccCheckListenerRuleExists(ctx context.Context, n string, res *elbv2.Ru return errors.New("Listener Rule not found") } - *res = *describe.Rules[0] + *res = describe.Rules[0] return nil } } func testAccCheckListenerRuleDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_lb_listener_rule" && rs.Type != "aws_alb_listener_rule" { continue } - describe, err := conn.DescribeRulesWithContext(ctx, &elbv2.DescribeRulesInput{ - RuleArns: []*string{aws.String(rs.Primary.ID)}, + describe, err := conn.DescribeRules(ctx, &elasticloadbalancingv2.DescribeRulesInput{ + RuleArns: []string{rs.Primary.ID}, }) if err == nil { @@ -1583,7 +2197,7 @@ func testAccCheckListenerRuleDestroy(ctx context.Context) resource.TestCheckFunc } // Verify the error - if tfawserr.ErrCodeEquals(err, elbv2.ErrCodeRuleNotFoundException) { + if errs.IsA[*awstypes.RuleNotFoundException](err) { return nil } else { return fmt.Errorf("Unexpected error checking LB Listener Rule destroyed: %s", err) @@ -1657,7 +2271,7 @@ resource "aws_lb_target_group" "test" { `, rName)) } -func testAccListenerRuleConfig_baseWithListener(rName string) string { +func testAccListenerRuleConfig_baseWithHTTPListener(rName string) string { return acctest.ConfigCompose(testAccListenerRuleConfig_base(rName), fmt.Sprintf(` resource "aws_lb_listener" "test" { load_balancer_arn = aws_lb.test.id @@ -1676,8 +2290,35 @@ resource "aws_lb_listener" "test" { `, rName)) } +func testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_base(rName), fmt.Sprintf(` +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } + + tags = { + Name = %[1]q + } +} + +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" +} +`, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) +} + func testAccListenerRuleConfig_basic(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), ` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` resource "aws_lb_listener_rule" "test" { listener_arn = aws_lb_listener.test.arn priority = 100 @@ -1696,6 +2337,62 @@ resource "aws_lb_listener_rule" "test" { `) } +func testAccListenerRuleConfig_forwardBasic(rName, targetName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "forward" + target_group_arn = aws_lb_target_group.%[2]s.arn + } + + condition { + path_pattern { + values = ["/static/*"] + } + } +} + +resource "aws_lb_target_group" "test1" { + name = "%[1]s-1" + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} + +resource "aws_lb_target_group" "test2" { + name = "%[1]s-2" + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} +`, rName, targetName)) +} + func testAccListenerRuleConfig_forwardWeighted(lbName, targetGroupName1 string, targetGroupName2 string) string { return fmt.Sprintf(` resource "aws_lb_listener_rule" "weighted" { @@ -2135,6 +2832,212 @@ resource "aws_security_group" "alb_test" { `, rName) } +func testAccListenerRuleConfig_actionForward_TargetGroupARN(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), ` +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "forward" + target_group_arn = aws_lb_target_group.test.arn + } + + condition { + path_pattern { + values = ["/static/*"] + } + } +} +`) +} + +func testAccListenerRuleConfig_actionForward_ForwardBlockBasic(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), ` +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "forward" + forward { + target_group { + arn = aws_lb_target_group.test.arn + } + } + } + + condition { + path_pattern { + values = ["/static/*"] + } + } +} +`) +} + +func testAccListenerRuleConfig_actionForward_ForwardBlockStickiness(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), ` +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "forward" + forward { + target_group { + arn = aws_lb_target_group.test.arn + } + + stickiness { + enabled = true + duration = 3600 + } + } + } + + condition { + path_pattern { + values = ["/static/*"] + } + } +} +`) +} + +func testAccListenerRuleConfig_actionForward_ForwardBlockWeightAndStickiness(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), ` +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "forward" + forward { + target_group { + arn = aws_lb_target_group.test.arn + weight = 2 + } + + stickiness { + enabled = true + duration = 3600 + } + } + } + + condition { + path_pattern { + values = ["/static/*"] + } + } +} +`) +} + +func testAccListenerRuleConfig_actionForward_ForwardBlockAddAction(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), ` +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "authenticate-oidc" + + authenticate_oidc { + authorization_endpoint = "https://example.com/authorization_endpoint" + client_id = "s6BhdRkqt3" + client_secret = "7Fjfp0ZBr1KtDRbnfVdmIw" + issuer = "https://example.com" + token_endpoint = "https://example.com/token_endpoint" + user_info_endpoint = "https://example.com/user_info_endpoint" + + authentication_request_extra_params = { + param = "test" + } + } + } + + action { + type = "forward" + forward { + target_group { + arn = aws_lb_target_group.test.arn + } + } + } + + condition { + path_pattern { + values = ["/static/*"] + } + } +} +`) +} + +func testAccListenerRuleConfig_actionForward_ForwardBlockMultiTargetWithIgnore(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), fmt.Sprintf(` +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "forward" + + forward { + target_group { + arn = aws_lb_target_group.test.arn + weight = 100 + } + + target_group { + arn = aws_lb_target_group.test2.arn + weight = 0 + } + } + } + + condition { + path_pattern { + values = ["/static/*"] + } + } + + lifecycle { + ignore_changes = [ + action[0].forward, + action[0].target_group_arn, + ] + } +} + +resource "aws_lb_target_group" "test2" { + name = "%[1]s-2" + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} +`, rName)) +} + func testAccListenerRuleConfig_changeForwardWeightedToBasic(lbName, targetGroupName1 string, targetGroupName2 string) string { return fmt.Sprintf(` resource "aws_lb_listener_rule" "weighted" { @@ -2629,7 +3532,7 @@ resource "aws_security_group" "alb_test" { } func testAccListenerRuleConfig_updatePriority(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), ` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` resource "aws_lb_listener_rule" "test" { listener_arn = aws_lb_listener.test.arn priority = 101 @@ -2649,7 +3552,7 @@ resource "aws_lb_listener_rule" "test" { } func testAccListenerRuleConfig_changeARN(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "test" { listener_arn = aws_lb_listener.test2.arn priority = 101 @@ -2684,7 +3587,8 @@ resource "aws_lb_listener" "test2" { } func testAccListenerRuleConfig_priorityFirst(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "first" { listener_arn = aws_lb_listener.test.arn @@ -2728,8 +3632,9 @@ resource "aws_lb_listener_rule" "third" { `, rName)) } -func testAccListenerRuleConfig_priorityLast(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` +func testAccListenerRuleConfig_priorityLastNoPriority(rName string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_priorityFirst(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "last" { listener_arn = aws_lb_listener.test.arn @@ -2751,11 +3656,12 @@ resource "aws_lb_listener_rule" "last" { `, rName)) } -func testAccListenerRuleConfig_priorityStatic(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` +func testAccListenerRuleConfig_priorityLastSpecifyPriority(rName, priority string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_priorityFirst(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "last" { listener_arn = aws_lb_listener.test.arn - priority = 7 + priority = %[2]s action { type = "forward" @@ -2772,11 +3678,11 @@ resource "aws_lb_listener_rule" "last" { Name = %[1]q } } -`, rName)) +`, rName, priority)) } func testAccListenerRuleConfig_priorityParallelism(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "parallelism" { count = 10 @@ -2801,7 +3707,7 @@ resource "aws_lb_listener_rule" "parallelism" { } func testAccListenerRuleConfig_priority50000(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "priority50000" { listener_arn = aws_lb_listener.test.arn priority = 50000 @@ -2826,7 +3732,7 @@ resource "aws_lb_listener_rule" "priority50000" { // priority out of range (1, 50000) func testAccListenerRuleConfig_priority50001(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "priority50001" { listener_arn = aws_lb_listener.test.arn @@ -2849,7 +3755,7 @@ resource "aws_lb_listener_rule" "priority50001" { } func testAccListenerRuleConfig_priorityInUse(rName string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "priority50000" { listener_arn = aws_lb_listener.test.arn priority = 50000 @@ -3864,7 +4770,7 @@ condition { } func testAccListenerRuleConfig_tags1(rName, tagKey1, tagValue1 string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "test" { listener_arn = aws_lb_listener.test.arn priority = 100 @@ -3888,7 +4794,7 @@ resource "aws_lb_listener_rule" "test" { } func testAccListenerRuleConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithListener(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), fmt.Sprintf(` resource "aws_lb_listener_rule" "test" { listener_arn = aws_lb_listener.test.arn priority = 100 diff --git a/internal/service/elbv2/listener_test.go b/internal/service/elbv2/listener_test.go index 457bb3fe013..ce31802724d 100644 --- a/internal/service/elbv2/listener_test.go +++ b/internal/service/elbv2/listener_test.go @@ -67,6 +67,9 @@ func TestAccELBV2Listener_Application_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, }, }, }) @@ -115,6 +118,9 @@ func TestAccELBV2Listener_Network_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, }, }, }) @@ -142,7 +148,7 @@ func TestAccELBV2Listener_Gateway_basic(t *testing.T) { resource.TestCheckNoResourceAttr(resourceName, "alpn_policy"), resource.TestCheckNoResourceAttr(resourceName, "certificate_arn"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "0"), // A Gateway Listener can only have one action, so the API never returns a value resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_cognito.#", "0"), @@ -163,6 +169,9 @@ func TestAccELBV2Listener_Gateway_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, }, }, }) @@ -221,6 +230,9 @@ func TestAccELBV2Listener_tags(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, }, { Config: testAccListenerConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), @@ -231,6 +243,14 @@ func TestAccELBV2Listener_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, { Config: testAccListenerConfig_tags1(rName, "key2", "value2"), Check: resource.ComposeAggregateTestCheckFunc( @@ -239,6 +259,67 @@ func TestAccELBV2Listener_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, + }, + }) +} + +func TestAccELBV2Listener_updateForwardBasic(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Listener + resourceName := "aws_lb_listener.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName = rName[:30] + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_forwardBasic(rName, "test1"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test1", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, + { + Config: testAccListenerConfig_forwardBasic(rName, "test2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test2", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, }, }) } @@ -265,7 +346,6 @@ func TestAccELBV2Listener_forwardWeighted(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), resource.TestCheckResourceAttr(resourceName, "port", "80"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "2"), @@ -289,7 +369,6 @@ func TestAccELBV2Listener_forwardWeighted(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), resource.TestCheckResourceAttr(resourceName, "port", "80"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "2"), @@ -313,13 +392,20 @@ func TestAccELBV2Listener_forwardWeighted(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), resource.TestCheckResourceAttr(resourceName, "port", "80"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test1", "arn"), resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, }, }) } @@ -342,11 +428,13 @@ func TestAccELBV2Listener_forwardTargetARNAndBlock(t *testing.T) { }) } -func TestAccELBV2Listener_Protocol_upd(t *testing.T) { +func TestAccELBV2Listener_ActionForward_TargetGroupARNToForwardBlock_NoChanges(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener resourceName := "aws_lb_listener.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -355,75 +443,58 @@ func TestAccELBV2Listener_Protocol_upd(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_basicUdp(rName), + Config: testAccListenerConfig_actionForward_TargetGroupARN(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), - resource.TestCheckResourceAttr(resourceName, "protocol", "UDP"), - resource.TestCheckResourceAttr(resourceName, "port", "514"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "0"), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, }, - }, - }) -} - -// TestAccELBV2Listener_backwardsCompatibility confirms that the resource type `aws_alb_listener` works -func TestAccELBV2Listener_backwardsCompatibility(t *testing.T) { - ctx := acctest.Context(t) - var conf awstypes.Listener - resourceName := "aws_alb_listener.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckListenerDestroy(ctx), - Steps: []resource.TestStep{ { - Config: testAccListenerConfig_backwardsCompatibility(rName), + Config: testAccListenerConfig_actionForward_ForwardBlockBasic(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_alb.test", "arn"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), - resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), - resource.TestCheckResourceAttr(resourceName, "port", "80"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), - resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_alb_target_group.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, }, }, }) } -func TestAccELBV2Listener_Protocol_https(t *testing.T) { +func TestAccELBV2Listener_ActionForward_ForwardBlock_AddStickiness(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) resourceName := "aws_lb_listener.test" - certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -432,43 +503,64 @@ func TestAccELBV2Listener_Protocol_https(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_https(rName, key, certificate), + Config: testAccListenerConfig_actionForward_ForwardBlockBasic(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), - resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), - resource.TestCheckResourceAttr(resourceName, "port", "443"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), - resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), - resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "ssl_policy", "ELBSecurityPolicy-2016-08"), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.#", "1"), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.mode", tfelbv2.MutualAuthenticationOff), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.ignore_client_certificate_expiry", "false"), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.trust_store_arn", ""), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, + }, + { + Config: testAccListenerConfig_actionForward_ForwardBlockStickiness(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "3600"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, }, }, }) } -func TestAccELBV2Listener_mutualAuthentication(t *testing.T) { +func TestAccELBV2Listener_ActionForward_ForwardBlock_RemoveStickiness(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) resourceName := "aws_lb_listener.test" - certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -477,45 +569,64 @@ func TestAccELBV2Listener_mutualAuthentication(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_mutualAuthentication(rName, key, certificate), + Config: testAccListenerConfig_actionForward_ForwardBlockStickiness(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.#", "1"), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.mode", tfelbv2.MutualAuthenticationVerify), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.ignore_client_certificate_expiry", "false"), - resource.TestCheckResourceAttrPair(resourceName, "mutual_authentication.0.trust_store_arn", "aws_lb_trust_store.test", "arn"), - - resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), - - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), - resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), - resource.TestCheckResourceAttr(resourceName, "port", "443"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), - resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), - resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "ssl_policy", "ELBSecurityPolicy-2016-08"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "3600"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, + }, + { + Config: testAccListenerConfig_actionForward_ForwardBlockBasic(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, }, }, }) } -func TestAccELBV2Listener_mutualAuthenticationPassthrough(t *testing.T) { +func TestAccELBV2Listener_ActionForward_TargetGroupARNToForwardBlock_WeightAndStickiness(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) resourceName := "aws_lb_listener.test" - certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -524,48 +635,58 @@ func TestAccELBV2Listener_mutualAuthenticationPassthrough(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_mutualAuthenticationPassthrough(rName, key, certificate), + Config: testAccListenerConfig_actionForward_TargetGroupARN(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.#", "1"), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.mode", tfelbv2.MutualAuthenticationPassthrough), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.ignore_client_certificate_expiry", "false"), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.trust_store_arn", ""), - - resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), - - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), - resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), - resource.TestCheckResourceAttr(resourceName, "port", "443"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "0"), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), - resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "ssl_policy", "ELBSecurityPolicy-2016-08"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, + { + Config: testAccListenerConfig_actionForward_ForwardBlockWeightAndStickiness(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "3600"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, }, }, }) } -func TestAccELBV2Listener_LoadBalancerARN_gatewayLoadBalancer(t *testing.T) { +func TestAccELBV2Listener_ActionForward_ForwardBlockToTargetGroupARN_NoChanges(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - lbResourceName := "aws_lb.test" resourceName := "aws_lb_listener.test" - - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -574,30 +695,58 @@ func TestAccELBV2Listener_LoadBalancerARN_gatewayLoadBalancer(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_arnGateway(rName), + Config: testAccListenerConfig_actionForward_ForwardBlockBasic(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", lbResourceName, "arn"), - resource.TestCheckResourceAttr(resourceName, "protocol", ""), - resource.TestCheckResourceAttr(resourceName, "port", "0"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - ), - }, + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, + }, + { + Config: testAccListenerConfig_actionForward_TargetGroupARN(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, }, }) } -func TestAccELBV2Listener_Protocol_tls(t *testing.T) { +func TestAccELBV2Listener_ActionForward_ForwardBlockToTargetGroupARN_WeightAndStickiness(t *testing.T) { ctx := acctest.Context(t) - var listener1 awstypes.Listener + var conf awstypes.Listener + resourceName := "aws_lb_listener.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_lb_listener.test" - - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -606,30 +755,58 @@ func TestAccELBV2Listener_Protocol_tls(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_protocolTLS(rName, key, certificate), + Config: testAccListenerConfig_actionForward_ForwardBlockWeightAndStickiness(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckListenerExists(ctx, resourceName, &listener1), - resource.TestCheckResourceAttr(resourceName, "protocol", "TLS"), - resource.TestCheckResourceAttr(resourceName, "alpn_policy", tfelbv2.AlpnPolicyHTTP2Preferred), - resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_acm_certificate.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "ssl_policy", "ELBSecurityPolicy-2016-08"), - resource.TestCheckResourceAttr(resourceName, "mutual_authentication.#", "0"), + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "3600"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, + }, + { + Config: testAccListenerConfig_actionForward_TargetGroupARN(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, }, }, }) } -func TestAccELBV2Listener_redirect(t *testing.T) { +func TestAccELBV2Listener_ActionForward_ForwardBlock_AddAction(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener resourceName := "aws_lb_listener.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -638,41 +815,66 @@ func TestAccELBV2Listener_redirect(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_redirect(rName), + Config: testAccListenerConfig_actionForward_ForwardBlockBasic(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), - resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), - resource.TestCheckResourceAttr(resourceName, "port", "80"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "redirect"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "false"), resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.host", "#{host}"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.path", "/#{path}"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.port", "443"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.protocol", "HTTPS"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.query", "#{query}"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.status_code", "HTTP_301"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, + }, + { + Config: testAccListenerConfig_actionForward_ForwardBlockAddAction(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "authenticate-oidc"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.1.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.authenticate_oidc.0.client_secret", + "default_action.1.target_group_arn", + }, }, }, }) } -func TestAccELBV2Listener_fixedResponse(t *testing.T) { +func TestAccELBV2Listener_ActionForward_ForwardBlock_RemoveAction(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener resourceName := "aws_lb_listener.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -681,40 +883,67 @@ func TestAccELBV2Listener_fixedResponse(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_fixedResponse(rName), + Config: testAccListenerConfig_actionForward_ForwardBlockAddAction(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "authenticate-oidc"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.1.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.target_group_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.authenticate_oidc.0.client_secret", + "default_action.1.target_group_arn", + }, + }, + { + Config: testAccListenerConfig_actionForward_ForwardBlockBasic(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), - resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), - resource.TestCheckResourceAttr(resourceName, "port", "80"), resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "fixed-response"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_group.0.arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.0.weight", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "false"), resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), - resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.0.content_type", "text/plain"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.0.message_body", "Fixed response content"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.0.status_code", "200"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.target_group_arn", + }, }, }, }) } -func TestAccELBV2Listener_cognito(t *testing.T) { +func TestAccELBV2Listener_ActionForward_IgnoreFields(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) resourceName := "aws_lb_listener.test" - certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName = rName[:30] + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -723,25 +952,22 @@ func TestAccELBV2Listener_cognito(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_cognito(rName, key, certificate), + Config: testAccListenerConfig_actionForward_ForwardBlockMultiTargetWithIgnore(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), - resource.TestCheckResourceAttr(resourceName, "port", "443"), - resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "authenticate-cognito"), - resource.TestCheckResourceAttrSet(resourceName, "default_action.0.authenticate_cognito.0.user_pool_arn"), - resource.TestCheckResourceAttrSet(resourceName, "default_action.0.authenticate_cognito.0.user_pool_client_id"), - resource.TestCheckResourceAttrSet(resourceName, "default_action.0.authenticate_cognito.0.user_pool_domain"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_cognito.0.authentication_request_extra_params.%", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_cognito.0.authentication_request_extra_params.param", "test"), - resource.TestCheckResourceAttr(resourceName, "default_action.1.type", "forward"), - resource.TestCheckResourceAttr(resourceName, "default_action.1.order", "2"), - resource.TestCheckResourceAttrPair(resourceName, "default_action.1.target_group_arn", "aws_lb_target_group.test", "arn"), - resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "port", "440"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_group.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.stickiness.0.duration", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), ), }, { @@ -753,12 +979,10 @@ func TestAccELBV2Listener_cognito(t *testing.T) { }) } -func TestAccELBV2Listener_oidc(t *testing.T) { +func TestAccELBV2Listener_Protocol_upd(t *testing.T) { ctx := acctest.Context(t) var conf awstypes.Listener - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) resourceName := "aws_lb_listener.test" - certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ @@ -768,47 +992,38 @@ func TestAccELBV2Listener_oidc(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_oidc(rName, key, certificate), + Config: testAccListenerConfig_basicUdp(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckListenerExists(ctx, resourceName, &conf), resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), - resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), - resource.TestCheckResourceAttr(resourceName, "port", "443"), - resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "authenticate-oidc"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.authorization_endpoint", "https://example.com/authorization_endpoint"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.client_id", "s6BhdRkqt3"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.client_secret", "7Fjfp0ZBr1KtDRbnfVdmIw"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.issuer", "https://example.com"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.token_endpoint", "https://example.com/token_endpoint"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.user_info_endpoint", "https://example.com/user_info_endpoint"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.authentication_request_extra_params.%", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.authentication_request_extra_params.param", "test"), - resource.TestCheckResourceAttr(resourceName, "default_action.1.order", "2"), - resource.TestCheckResourceAttr(resourceName, "default_action.1.type", "forward"), - resource.TestCheckResourceAttrPair(resourceName, "default_action.1.target_group_arn", "aws_lb_target_group.test", "arn"), - resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "protocol", "UDP"), + resource.TestCheckResourceAttr(resourceName, "port", "514"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"default_action.0.authenticate_oidc.0.client_secret"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, }, }, }) } -func TestAccELBV2Listener_DefaultAction_defaultOrder(t *testing.T) { +// TestAccELBV2Listener_backwardsCompatibility confirms that the resource type `aws_alb_listener` works +func TestAccELBV2Listener_backwardsCompatibility(t *testing.T) { ctx := acctest.Context(t) - var listener awstypes.Listener - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) - certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + var conf awstypes.Listener + resourceName := "aws_alb_listener.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_lb_listener.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -817,31 +1032,42 @@ func TestAccELBV2Listener_DefaultAction_defaultOrder(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_defaultAction_defaultOrder(rName, key, certificate), + Config: testAccListenerConfig_backwardsCompatibility(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckListenerExists(ctx, resourceName, &listener), - resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.1.order", "2"), + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_alb.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "port", "80"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_alb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_cognito.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"default_action.0.authenticate_oidc.0.client_secret"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, }, }, }) } -func TestAccELBV2Listener_DefaultAction_specifyOrder(t *testing.T) { +func TestAccELBV2Listener_Protocol_https(t *testing.T) { ctx := acctest.Context(t) - var listener awstypes.Listener + var conf awstypes.Listener key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + resourceName := "aws_lb_listener.test" certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_lb_listener.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -850,32 +1076,45 @@ func TestAccELBV2Listener_DefaultAction_specifyOrder(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_defaultAction_specifyOrder(rName, key, certificate), + Config: testAccListenerConfig_https(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckListenerExists(ctx, resourceName, &listener), - resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "2"), - resource.TestCheckResourceAttr(resourceName, "default_action.1.order", "4"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"default_action.0.authenticate_oidc.0.client_secret"}, - }, - }, - }) -} - -// Reference: https://github.com/hashicorp/terraform-provider-aws/issues/6171 -func TestAccELBV2Listener_DefaultAction_actionDisappears(t *testing.T) { + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "port", "443"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy", "ELBSecurityPolicy-2016-08"), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.mode", tfelbv2.MutualAuthenticationOff), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.ignore_client_certificate_expiry", "false"), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.trust_store_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, + }, + }) +} + +func TestAccELBV2Listener_mutualAuthentication(t *testing.T) { ctx := acctest.Context(t) - var listener awstypes.Listener + var conf awstypes.Listener key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + resourceName := "aws_lb_listener.test" certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_lb_listener.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -884,225 +1123,1037 @@ func TestAccELBV2Listener_DefaultAction_actionDisappears(t *testing.T) { CheckDestroy: testAccCheckListenerDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccListenerConfig_defaultAction_defaultOrder(rName, key, certificate), + Config: testAccListenerConfig_mutualAuthentication(rName, key, certificate), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckListenerExists(ctx, resourceName, &listener), - resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), - resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), - resource.TestCheckResourceAttr(resourceName, "default_action.1.order", "2"), - testAccCheckListenerDefaultActionOrderDisappears(ctx, &listener, 1), + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.mode", tfelbv2.MutualAuthenticationVerify), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.ignore_client_certificate_expiry", "false"), + resource.TestCheckResourceAttrPair(resourceName, "mutual_authentication.0.trust_store_arn", "aws_lb_trust_store.test", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "port", "443"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy", "ELBSecurityPolicy-2016-08"), ), - ExpectNonEmptyPlan: true, - ConfigPlanChecks: resource.ConfigPlanChecks{ - PostApplyPostRefresh: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), - // TODO: change `default_action[0]` - // TODO: add `default_action[1]` - }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", }, }, }, }) } -func TestAccELBV2Listener_EmptyDefaultAction(t *testing.T) { - t.Parallel() +func TestAccELBV2Listener_mutualAuthenticationPassthrough(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Listener + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + resourceName := "aws_lb_listener.test" + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - testcases := map[awstypes.ActionTypeEnum]struct { - actionType awstypes.ActionTypeEnum - expectedError *regexp.Regexp - }{ - awstypes.ActionTypeEnumForward: { - actionType: awstypes.ActionTypeEnumForward, - expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Either %q or %q must be specified when %q is %q.", - "default_action[0].target_group_arn", "default_action[0].forward", - "default_action[0].type", - awstypes.ActionTypeEnumForward, - ))), + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_mutualAuthenticationPassthrough(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.mode", tfelbv2.MutualAuthenticationPassthrough), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.ignore_client_certificate_expiry", "false"), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.0.trust_store_arn", ""), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "port", "443"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.target_group_arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy", "ELBSecurityPolicy-2016-08"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, }, + }) +} - awstypes.ActionTypeEnumAuthenticateOidc: { - actionType: awstypes.ActionTypeEnumAuthenticateOidc, - expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Attribute %q must be specified when %q is %q.", - "default_action[0].authenticate_oidc", - "default_action[0].type", - awstypes.ActionTypeEnumAuthenticateOidc, - ))), - }, +func TestAccELBV2Listener_LoadBalancerARN_gatewayLoadBalancer(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Listener + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + lbResourceName := "aws_lb.test" + resourceName := "aws_lb_listener.test" - awstypes.ActionTypeEnumAuthenticateCognito: { - actionType: awstypes.ActionTypeEnumAuthenticateCognito, - expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Attribute %q must be specified when %q is %q.", - "default_action[0].authenticate_cognito", - "default_action[0].type", - awstypes.ActionTypeEnumAuthenticateCognito, - ))), - }, + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } - awstypes.ActionTypeEnumRedirect: { - actionType: awstypes.ActionTypeEnumRedirect, - expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Attribute %q must be specified when %q is %q.", - "default_action[0].redirect", - "default_action[0].type", - awstypes.ActionTypeEnumRedirect, - ))), + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_arnGateway(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", lbResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "protocol", ""), + resource.TestCheckResourceAttr(resourceName, "port", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, }, + }) +} - awstypes.ActionTypeEnumFixedResponse: { - actionType: awstypes.ActionTypeEnumFixedResponse, - expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Attribute %q must be specified when %q is %q.", - "default_action[0].fixed_response", - "default_action[0].type", - awstypes.ActionTypeEnumFixedResponse, - ))), - }, +func TestAccELBV2Listener_Protocol_tls(t *testing.T) { + ctx := acctest.Context(t) + var listener1 awstypes.Listener + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lb_listener.test" + + if testing.Short() { + t.Skip("skipping long-running test in short mode") } - for name, testcase := range testcases { //nolint:paralleltest // uses t.Setenv - testcase := testcase + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_protocolTLS(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &listener1), + resource.TestCheckResourceAttr(resourceName, "protocol", "TLS"), + resource.TestCheckResourceAttr(resourceName, "alpn_policy", tfelbv2.AlpnPolicyHTTP2Preferred), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_acm_certificate.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy", "ELBSecurityPolicy-2016-08"), + resource.TestCheckResourceAttr(resourceName, "mutual_authentication.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.forward", + }, + }, + }, + }) +} - t.Run(string(name), func(t *testing.T) { - ctx := acctest.Context(t) - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) +func TestAccELBV2Listener_redirect(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Listener + resourceName := "aws_lb_listener.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckListenerDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccListenerConfig_EmptyDefaultAction(rName, testcase.actionType), - ExpectError: testcase.expectedError, - }, - }, - }) - }) - } + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_redirect(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "port", "80"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "redirect"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.host", "#{host}"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.path", "/#{path}"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.port", "443"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.query", "#{query}"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.0.status_code", "HTTP_301"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccELBV2Listener_fixedResponse(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Listener + resourceName := "aws_lb_listener.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_fixedResponse(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "port", "80"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "fixed-response"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.target_group_arn", ""), + resource.TestCheckResourceAttr(resourceName, "default_action.0.redirect.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.0.content_type", "text/plain"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.0.message_body", "Fixed response content"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.fixed_response.0.status_code", "200"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccELBV2Listener_cognito(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Listener + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + resourceName := "aws_lb_listener.test" + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_cognito(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "port", "443"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "authenticate-cognito"), + resource.TestCheckResourceAttrSet(resourceName, "default_action.0.authenticate_cognito.0.user_pool_arn"), + resource.TestCheckResourceAttrSet(resourceName, "default_action.0.authenticate_cognito.0.user_pool_client_id"), + resource.TestCheckResourceAttrSet(resourceName, "default_action.0.authenticate_cognito.0.user_pool_domain"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_cognito.0.authentication_request_extra_params.%", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_cognito.0.authentication_request_extra_params.param", "test"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.1.target_group_arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.1.forward", + }, + }, + }, + }) +} + +func TestAccELBV2Listener_oidc(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Listener + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + resourceName := "aws_lb_listener.test" + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_oidc(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "port", "443"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "authenticate-oidc"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.authorization_endpoint", "https://example.com/authorization_endpoint"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.client_id", "s6BhdRkqt3"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.client_secret", "7Fjfp0ZBr1KtDRbnfVdmIw"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.issuer", "https://example.com"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.token_endpoint", "https://example.com/token_endpoint"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.user_info_endpoint", "https://example.com/user_info_endpoint"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.authentication_request_extra_params.%", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.authenticate_oidc.0.authentication_request_extra_params.param", "test"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.1.target_group_arn", "aws_lb_target_group.test", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", "aws_iam_server_certificate.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.authenticate_oidc.0.client_secret", + "default_action.1.forward", + }, + }, + }, + }) +} + +func TestAccELBV2Listener_DefaultAction_defaultOrder(t *testing.T) { + ctx := acctest.Context(t) + var listener awstypes.Listener + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lb_listener.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_defaultAction_defaultOrder(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &listener), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.order", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.authenticate_oidc.0.client_secret", + "default_action.1.forward", + }, + }, + }, + }) +} + +func TestAccELBV2Listener_DefaultAction_specifyOrder(t *testing.T) { + ctx := acctest.Context(t) + var listener awstypes.Listener + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lb_listener.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_defaultAction_specifyOrder(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &listener), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.order", "4"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.authenticate_oidc.0.client_secret", + "default_action.1.forward", + }, + }, + }, + }) +} + +// Reference: https://github.com/hashicorp/terraform-provider-aws/issues/6171 +func TestAccELBV2Listener_DefaultAction_actionDisappears(t *testing.T) { + ctx := acctest.Context(t) + var listener awstypes.Listener + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lb_listener.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_defaultAction_defaultOrder(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &listener), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.order", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.1.order", "2"), + testAccCheckListenerDefaultActionOrderDisappears(ctx, &listener, 1), + ), + ExpectNonEmptyPlan: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + // TODO: change `default_action[0]` + // TODO: add `default_action[1]` + }, + }, + }, + }, + }) +} + +func TestAccELBV2Listener_EmptyDefaultAction(t *testing.T) { + t.Parallel() + + testcases := map[awstypes.ActionTypeEnum]struct { + actionType awstypes.ActionTypeEnum + expectedError *regexp.Regexp + }{ + awstypes.ActionTypeEnumForward: { + actionType: awstypes.ActionTypeEnumForward, + expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Either %q or %q must be specified when %q is %q.", + "default_action[0].target_group_arn", "default_action[0].forward", + "default_action[0].type", + awstypes.ActionTypeEnumForward, + ))), + }, + + awstypes.ActionTypeEnumAuthenticateOidc: { + actionType: awstypes.ActionTypeEnumAuthenticateOidc, + expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Attribute %q must be specified when %q is %q.", + "default_action[0].authenticate_oidc", + "default_action[0].type", + awstypes.ActionTypeEnumAuthenticateOidc, + ))), + }, + + awstypes.ActionTypeEnumAuthenticateCognito: { + actionType: awstypes.ActionTypeEnumAuthenticateCognito, + expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Attribute %q must be specified when %q is %q.", + "default_action[0].authenticate_cognito", + "default_action[0].type", + awstypes.ActionTypeEnumAuthenticateCognito, + ))), + }, + + awstypes.ActionTypeEnumRedirect: { + actionType: awstypes.ActionTypeEnumRedirect, + expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Attribute %q must be specified when %q is %q.", + "default_action[0].redirect", + "default_action[0].type", + awstypes.ActionTypeEnumRedirect, + ))), + }, + + awstypes.ActionTypeEnumFixedResponse: { + actionType: awstypes.ActionTypeEnumFixedResponse, + expectedError: regexache.MustCompile(regexp.QuoteMeta(fmt.Sprintf("Attribute %q must be specified when %q is %q.", + "default_action[0].fixed_response", + "default_action[0].type", + awstypes.ActionTypeEnumFixedResponse, + ))), + }, + } + + for name, testcase := range testcases { //nolint:paralleltest // uses t.Setenv + testcase := testcase + + t.Run(string(name), func(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, tfelbv2.AwsSdkId), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_EmptyDefaultAction(rName, testcase.actionType), + ExpectError: testcase.expectedError, + }, + }, + }) + }) + } +} + +func testAccCheckListenerDefaultActionOrderDisappears(ctx context.Context, listener *awstypes.Listener, actionOrderToDelete int) resource.TestCheckFunc { + return func(s *terraform.State) error { + var newDefaultActions []awstypes.Action + + for i, action := range listener.DefaultActions { + if int(aws.ToInt32(action.Order)) == actionOrderToDelete { + newDefaultActions = slices.Delete(listener.DefaultActions, i, i+1) + break + } + } + + if len(newDefaultActions) == 0 { + return fmt.Errorf("Unable to find default action order %d from default actions: %#v", actionOrderToDelete, listener.DefaultActions) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) + + input := &elasticloadbalancingv2.ModifyListenerInput{ + DefaultActions: newDefaultActions, + ListenerArn: listener.ListenerArn, + } + + _, err := conn.ModifyListener(ctx, input) + + return err + } +} + +func testAccCheckListenerExists(ctx context.Context, n string, v *awstypes.Listener) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) + + output, err := tfelbv2.FindListenerByARN(ctx, conn, rs.Primary.ID) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccCheckListenerDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_lb_listener" && rs.Type != "aws_alb_listener" { + continue + } + + _, err := tfelbv2.FindListenerByARN(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("ELBv2 Listener %s still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccListenerConfig_base(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` +resource "aws_security_group" "test" { + name = %[1]q + description = "Used for ALB Testing" + vpc_id = aws_vpc.test.id + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = %[1]q + } +} +`, rName)) +} + +func testAccListenerConfig_Application_basic(rName string) string { + return acctest.ConfigCompose( + testAccListenerConfig_base(rName), fmt.Sprintf(` +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + port = "80" + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} + +resource "aws_lb" "test" { + name = %[1]q + load_balancer_type = "application" + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + + idle_timeout = 30 + enable_deletion_protection = false + + tags = { + Name = %[1]q + } +} + +resource "aws_lb_target_group" "test" { + name = %[1]q + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } + + tags = { + Name = %[1]q + } +} +`, rName)) +} + +func testAccListenerConfig_Network_basic(rName string) string { + return acctest.ConfigCompose( + testAccListenerConfig_base(rName), fmt.Sprintf(` +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "TCP" + port = "80" + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} + +resource "aws_lb" "test" { + name = %[1]q + load_balancer_type = "network" + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + + idle_timeout = 30 + enable_deletion_protection = false + + tags = { + Name = %[1]q + } +} + +resource "aws_lb_target_group" "test" { + name = %[1]q + port = 8080 + protocol = "TCP" + vpc_id = aws_vpc.test.id + + health_check { + interval = 10 + port = 8081 + protocol = "TCP" + healthy_threshold = 3 + unhealthy_threshold = 3 + } + + tags = { + Name = %[1]q + } +} +`, rName)) +} + +func testAccListenerConfig_Gateway_basic(rName string) string { + return acctest.ConfigCompose( + testAccListenerConfig_base(rName), fmt.Sprintf(` +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} + +resource "aws_lb" "test" { + name = %[1]q + load_balancer_type = "gateway" + subnets = aws_subnet.test[*].id + + idle_timeout = 30 + enable_deletion_protection = false + + tags = { + Name = %[1]q + } +} + +resource "aws_lb_target_group" "test" { + name = %[1]q + port = 6081 + protocol = "GENEVE" + vpc_id = aws_vpc.test.id + + health_check { + interval = 10 + port = 8081 + protocol = "TCP" + healthy_threshold = 3 + unhealthy_threshold = 3 + } + + tags = { + Name = %[1]q + } +} +`, rName)) +} + +func testAccListenerConfig_forwardBasic(rName, targetName string) string { + return acctest.ConfigCompose(testAccListenerConfig_base(rName), fmt.Sprintf(` +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTP" + port = "440" + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.%[2]s.arn + } +} + +resource "aws_lb" "test" { + name = %[1]q + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + + idle_timeout = 30 + enable_deletion_protection = false +} + +resource "aws_lb_target_group" "test1" { + name = "%[1]s-1" + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} + +resource "aws_lb_target_group" "test2" { + name = "%[1]s-2" + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} +`, rName, targetName)) } -func testAccCheckListenerDefaultActionOrderDisappears(ctx context.Context, listener *awstypes.Listener, actionOrderToDelete int) resource.TestCheckFunc { - return func(s *terraform.State) error { - var newDefaultActions []awstypes.Action +func testAccListenerConfig_forwardWeighted(rName, rName2 string) string { + return acctest.ConfigCompose(testAccListenerConfig_base(rName), fmt.Sprintf(` +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTP" + port = "80" - for i, action := range listener.DefaultActions { - if int(aws.ToInt32(action.Order)) == actionOrderToDelete { - newDefaultActions = slices.Delete(listener.DefaultActions, i, i+1) - break - } - } + default_action { + type = "forward" - if len(newDefaultActions) == 0 { - return fmt.Errorf("Unable to find default action order %d from default actions: %#v", actionOrderToDelete, listener.DefaultActions) - } + forward { + target_group { + arn = aws_lb_target_group.test1.arn + weight = 1 + } - conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) + target_group { + arn = aws_lb_target_group.test2.arn + weight = 1 + } + } + } +} - input := &elasticloadbalancingv2.ModifyListenerInput{ - DefaultActions: newDefaultActions, - ListenerArn: listener.ListenerArn, - } +resource "aws_lb" "test" { + name = %[1]q + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id - _, err := conn.ModifyListener(ctx, input) + idle_timeout = 30 + enable_deletion_protection = false - return err - } + tags = { + Name = %[1]q + } } -func testAccCheckListenerExists(ctx context.Context, n string, v *awstypes.Listener) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } +resource "aws_lb_target_group" "test1" { + name = %[1]q + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id - conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } - output, err := tfelbv2.FindListenerByARN(ctx, conn, rs.Primary.ID) + tags = { + Name = %[1]q + } +} - if err != nil { - return err - } +resource "aws_lb_target_group" "test2" { + name = %[2]q + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id - *v = *output + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } - return nil - } + tags = { + Name = %[2]q + } +} +`, rName, rName2)) } -func testAccCheckListenerDestroy(ctx context.Context) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) +func testAccListenerConfig_changeForwardWeightedStickiness(rName, rName2 string) string { + return acctest.ConfigCompose(testAccListenerConfig_base(rName), fmt.Sprintf(` +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTP" + port = "80" - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_lb_listener" && rs.Type != "aws_alb_listener" { - continue - } + default_action { + type = "forward" - _, err := tfelbv2.FindListenerByARN(ctx, conn, rs.Primary.ID) + forward { + target_group { + arn = aws_lb_target_group.test1.arn + weight = 1 + } - if tfresource.NotFound(err) { - continue - } + target_group { + arn = aws_lb_target_group.test2.arn + weight = 1 + } - if err != nil { - return err - } + stickiness { + enabled = true + duration = 3600 + } + } + } +} - return fmt.Errorf("ELBv2 Listener %s still exists", rs.Primary.ID) - } +resource "aws_lb" "test" { + name = %[1]q + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id - return nil - } + idle_timeout = 30 + enable_deletion_protection = false + + tags = { + Name = %[1]q + } } -func testAccListenerConfig_base(rName string) string { - return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` -resource "aws_security_group" "test" { - name = %[1]q - description = "Used for ALB Testing" - vpc_id = aws_vpc.test.id +resource "aws_lb_target_group" "test1" { + name = %[1]q + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id - ingress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" } - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + tags = { + Name = %[1]q + } +} + +resource "aws_lb_target_group" "test2" { + name = %[2]q + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" } tags = { Name = %[1]q } } -`, rName)) +`, rName, rName2)) } -func testAccListenerConfig_Application_basic(rName string) string { +func testAccListenerConfig_forwardTargetARNAndBlock(rName string) string { return acctest.ConfigCompose( - testAccListenerConfig_base(rName), fmt.Sprintf(` + testAccListenerConfig_base(rName), + fmt.Sprintf(` resource "aws_lb_listener" "test" { load_balancer_arn = aws_lb.test.id - port = "80" + protocol = "HTTP" + port = "440" default_action { - target_group_arn = aws_lb_target_group.test.id - type = "forward" + type = "forward" + + target_group_arn = aws_lb_target_group.test.arn + + forward { + target_group { + arn = aws_lb_target_group.test.arn + weight = 1 + } + + stickiness { + enabled = true + duration = 3600 + } + } } } resource "aws_lb" "test" { - name = %[1]q - load_balancer_type = "application" - internal = true - security_groups = [aws_security_group.test.id] - subnets = aws_subnet.test[*].id + name = %[1]q + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id idle_timeout = 30 enable_deletion_protection = false @@ -1136,26 +2187,29 @@ resource "aws_lb_target_group" "test" { `, rName)) } -func testAccListenerConfig_Network_basic(rName string) string { +func testAccListenerConfig_actionForward_TargetGroupARN(rName, key, certificate string) string { return acctest.ConfigCompose( - testAccListenerConfig_base(rName), fmt.Sprintf(` + testAccListenerConfig_base(rName), + fmt.Sprintf(` resource "aws_lb_listener" "test" { load_balancer_arn = aws_lb.test.id - protocol = "TCP" - port = "80" + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn + + default_action { + type = "forward" - default_action { - target_group_arn = aws_lb_target_group.test.id - type = "forward" + target_group_arn = aws_lb_target_group.test.arn } } resource "aws_lb" "test" { - name = %[1]q - load_balancer_type = "network" - internal = true - security_groups = [aws_security_group.test.id] - subnets = aws_subnet.test[*].id + name = %[1]q + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id idle_timeout = 30 enable_deletion_protection = false @@ -1168,40 +2222,60 @@ resource "aws_lb" "test" { resource "aws_lb_target_group" "test" { name = %[1]q port = 8080 - protocol = "TCP" + protocol = "HTTP" vpc_id = aws_vpc.test.id health_check { - interval = 10 + path = "/health" + interval = 60 port = 8081 - protocol = "TCP" + protocol = "HTTP" + timeout = 3 healthy_threshold = 3 unhealthy_threshold = 3 + matcher = "200-299" } tags = { Name = %[1]q } } -`, rName)) + +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" +} + `, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) } -func testAccListenerConfig_Gateway_basic(rName string) string { +func testAccListenerConfig_actionForward_ForwardBlockBasic(rName, key, certificate string) string { return acctest.ConfigCompose( - testAccListenerConfig_base(rName), fmt.Sprintf(` + testAccListenerConfig_base(rName), + fmt.Sprintf(` resource "aws_lb_listener" "test" { load_balancer_arn = aws_lb.test.id + protocol = "HTTPS" + port = "440" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn default_action { - target_group_arn = aws_lb_target_group.test.id - type = "forward" + type = "forward" + + forward { + target_group { + arn = aws_lb_target_group.test.arn + } + } } } resource "aws_lb" "test" { - name = %[1]q - load_balancer_type = "gateway" - subnets = aws_subnet.test[*].id + name = %[1]q + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id idle_timeout = 30 enable_deletion_protection = false @@ -1213,44 +2287,56 @@ resource "aws_lb" "test" { resource "aws_lb_target_group" "test" { name = %[1]q - port = 6081 - protocol = "GENEVE" + port = 8080 + protocol = "HTTP" vpc_id = aws_vpc.test.id health_check { - interval = 10 + path = "/health" + interval = 60 port = 8081 - protocol = "TCP" + protocol = "HTTP" + timeout = 3 healthy_threshold = 3 unhealthy_threshold = 3 + matcher = "200-299" } tags = { Name = %[1]q } } -`, rName)) + +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" +} +`, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) } -func testAccListenerConfig_forwardWeighted(rName, rName2 string) string { - return acctest.ConfigCompose(testAccListenerConfig_base(rName), fmt.Sprintf(` +func testAccListenerConfig_actionForward_ForwardBlockStickiness(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerConfig_base(rName), + fmt.Sprintf(` resource "aws_lb_listener" "test" { load_balancer_arn = aws_lb.test.id - protocol = "HTTP" - port = "80" + protocol = "HTTPS" + port = "440" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn default_action { type = "forward" forward { target_group { - arn = aws_lb_target_group.test1.arn - weight = 1 + arn = aws_lb_target_group.test.arn } - target_group { - arn = aws_lb_target_group.test2.arn - weight = 1 + stickiness { + enabled = true + duration = 3600 } } } @@ -1270,7 +2356,7 @@ resource "aws_lb" "test" { } } -resource "aws_lb_target_group" "test1" { +resource "aws_lb_target_group" "test" { name = %[1]q port = 8080 protocol = "HTTP" @@ -1292,49 +2378,32 @@ resource "aws_lb_target_group" "test1" { } } -resource "aws_lb_target_group" "test2" { - name = %[2]q - port = 8080 - protocol = "HTTP" - vpc_id = aws_vpc.test.id - - health_check { - path = "/health" - interval = 60 - port = 8081 - protocol = "HTTP" - timeout = 3 - healthy_threshold = 3 - unhealthy_threshold = 3 - matcher = "200-299" - } - - tags = { - Name = %[2]q - } +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" } -`, rName, rName2)) +`, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) } -func testAccListenerConfig_changeForwardWeightedStickiness(rName, rName2 string) string { - return acctest.ConfigCompose(testAccListenerConfig_base(rName), fmt.Sprintf(` +func testAccListenerConfig_actionForward_ForwardBlockWeightAndStickiness(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerConfig_base(rName), + fmt.Sprintf(` resource "aws_lb_listener" "test" { load_balancer_arn = aws_lb.test.id - protocol = "HTTP" - port = "80" + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn default_action { type = "forward" forward { target_group { - arn = aws_lb_target_group.test1.arn - weight = 1 - } - - target_group { - arn = aws_lb_target_group.test2.arn - weight = 1 + arn = aws_lb_target_group.test.arn + weight = 2 } stickiness { @@ -1359,7 +2428,7 @@ resource "aws_lb" "test" { } } -resource "aws_lb_target_group" "test1" { +resource "aws_lb_target_group" "test" { name = %[1]q port = 8080 protocol = "HTTP" @@ -1381,8 +2450,69 @@ resource "aws_lb_target_group" "test1" { } } -resource "aws_lb_target_group" "test2" { - name = %[2]q +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" +} +`, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) +} + +func testAccListenerConfig_actionForward_ForwardBlockAddAction(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerConfig_base(rName), + fmt.Sprintf(` +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn + + default_action { + type = "authenticate-oidc" + + authenticate_oidc { + authorization_endpoint = "https://example.com/authorization_endpoint" + client_id = "s6BhdRkqt3" + client_secret = "7Fjfp0ZBr1KtDRbnfVdmIw" + issuer = "https://example.com" + token_endpoint = "https://example.com/token_endpoint" + user_info_endpoint = "https://example.com/user_info_endpoint" + + authentication_request_extra_params = { + param = "test" + } + } + } + + default_action { + type = "forward" + + forward { + target_group { + arn = aws_lb_target_group.test.arn + } + } + } +} + +resource "aws_lb" "test" { + name = %[1]q + internal = true + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + + idle_timeout = 30 + enable_deletion_protection = false + + tags = { + Name = %[1]q + } +} + +resource "aws_lb_target_group" "test" { + name = %[1]q port = 8080 protocol = "HTTP" vpc_id = aws_vpc.test.id @@ -1402,35 +2532,48 @@ resource "aws_lb_target_group" "test2" { Name = %[1]q } } -`, rName, rName2)) + +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" +} +`, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) } -func testAccListenerConfig_forwardTargetARNAndBlock(rName string) string { +func testAccListenerConfig_actionForward_ForwardBlockMultiTargetWithIgnore(rName, key, certificate string) string { return acctest.ConfigCompose( testAccListenerConfig_base(rName), fmt.Sprintf(` resource "aws_lb_listener" "test" { load_balancer_arn = aws_lb.test.id - protocol = "HTTP" + protocol = "HTTPS" port = "440" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn default_action { type = "forward" - target_group_arn = aws_lb_target_group.test.arn - forward { target_group { arn = aws_lb_target_group.test.arn - weight = 1 + weight = 100 } - stickiness { - enabled = true - duration = 3600 + target_group { + arn = aws_lb_target_group.test2.arn + weight = 0 } } } + + lifecycle { + ignore_changes = [ + default_action[0].forward, + default_action[0].target_group_arn, + ] + } } resource "aws_lb" "test" { @@ -1468,7 +2611,35 @@ resource "aws_lb_target_group" "test" { Name = %[1]q } } -`, rName)) + +resource "aws_lb_target_group" "test2" { + name = "%[1]s-2" + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } + + tags = { + Name = %[1]q + } +} + +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" +} +`, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) } func testAccListenerConfig_changeForwardWeightedToBasic(rName, rName2 string) string { @@ -2236,8 +3407,7 @@ resource "aws_lb_listener" "test" { certificate_arn = aws_iam_server_certificate.test.arn default_action { - order = 1 - type = "authenticate-oidc" + type = "authenticate-oidc" authenticate_oidc { authorization_endpoint = "https://example.com/authorization_endpoint" @@ -2254,7 +3424,6 @@ resource "aws_lb_listener" "test" { } default_action { - order = 2 type = "forward" target_group_arn = aws_lb_target_group.test.arn } diff --git a/website/docs/r/lb_listener.html.markdown b/website/docs/r/lb_listener.html.markdown index c98b41fea46..e3a16fed28d 100644 --- a/website/docs/r/lb_listener.html.markdown +++ b/website/docs/r/lb_listener.html.markdown @@ -278,10 +278,19 @@ The following arguments are optional: * `authenticate_cognito` - (Optional) Configuration block for using Amazon Cognito to authenticate users. Specify only when `type` is `authenticate-cognito`. Detailed below. * `authenticate_oidc` - (Optional) Configuration block for an identity provider that is compliant with OpenID Connect (OIDC). Specify only when `type` is `authenticate-oidc`. Detailed below. * `fixed_response` - (Optional) Information for creating an action that returns a custom HTTP response. Required if `type` is `fixed-response`. -* `forward` - (Optional) Configuration block for creating an action that distributes requests among one or more target groups. Specify only if `type` is `forward`. If you specify both `forward` block and `target_group_arn` attribute, you can specify only one target group using `forward` and it must be the same target group specified in `target_group_arn`. Detailed below. -* `order` - (Optional) Order for the action. This value is required for rules with multiple actions. The action with the lowest value for order is performed first. Valid values are between `1` and `50000`. +* `forward` - (Optional) Configuration block for creating an action that distributes requests among one or more target groups. + Specify only if `type` is `forward`. + Cannot be specified with `target_group_arn`. + Detailed below. +* `order` - (Optional) Order for the action. + The action with the lowest value for order is performed first. + Valid values are between `1` and `50000`. + Defaults to the position in the list of actions. * `redirect` - (Optional) Configuration block for creating a redirect action. Required if `type` is `redirect`. Detailed below. -* `target_group_arn` - (Optional) ARN of the Target Group to which to route traffic. Specify only if `type` is `forward` and you want to route to a single target group. To route to one or more target groups, use a `forward` block instead. +* `target_group_arn` - (Optional) ARN of the Target Group to which to route traffic. + Specify only if `type` is `forward` and you want to route to a single target group. + To route to one or more target groups, use a `forward` block instead. + Cannot be specified with `forward`. #### authenticate_cognito diff --git a/website/docs/r/lb_listener_rule.html.markdown b/website/docs/r/lb_listener_rule.html.markdown index f3f610075d5..f6f117d7432 100644 --- a/website/docs/r/lb_listener_rule.html.markdown +++ b/website/docs/r/lb_listener_rule.html.markdown @@ -219,12 +219,21 @@ This resource supports the following arguments: Action Blocks (for `action`) support the following: * `type` - (Required) The type of routing action. Valid values are `forward`, `redirect`, `fixed-response`, `authenticate-cognito` and `authenticate-oidc`. -* `target_group_arn` - (Optional) The ARN of the Target Group to which to route traffic. Specify only if `type` is `forward` and you want to route to a single target group. To route to one or more target groups, use a `forward` block instead. -* `forward` - (Optional) Information for creating an action that distributes requests among one or more target groups. Specify only if `type` is `forward`. If you specify both `forward` block and `target_group_arn` attribute, you can specify only one target group using `forward` and it must be the same target group specified in `target_group_arn`. -* `redirect` - (Optional) Information for creating a redirect action. Required if `type` is `redirect`. -* `fixed_response` - (Optional) Information for creating an action that returns a custom HTTP response. Required if `type` is `fixed-response`. * `authenticate_cognito` - (Optional) Information for creating an authenticate action using Cognito. Required if `type` is `authenticate-cognito`. * `authenticate_oidc` - (Optional) Information for creating an authenticate action using OIDC. Required if `type` is `authenticate-oidc`. +* `fixed_response` - (Optional) Information for creating an action that returns a custom HTTP response. Required if `type` is `fixed-response`. +* `forward` - (Optional) Configuration block for creating an action that distributes requests among one or more target groups. + Specify only if `type` is `forward`. + Cannot be specified with `target_group_arn`. +* `order` - (Optional) Order for the action. + The action with the lowest value for order is performed first. + Valid values are between `1` and `50000`. + Defaults to the position in the list of actions. +* `redirect` - (Optional) Information for creating a redirect action. Required if `type` is `redirect`. +* `target_group_arn` - (Optional) ARN of the Target Group to which to route traffic. + Specify only if `type` is `forward` and you want to route to a single target group. + To route to one or more target groups, use a `forward` block instead. + Cannot be specified with `forward`. Forward Blocks (for `forward`) support the following: