diff --git a/.changelog/39865.txt b/.changelog/39865.txt new file mode 100644 index 00000000000..33f07353fc5 --- /dev/null +++ b/.changelog/39865.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_lb_listener_rule +``` diff --git a/internal/provider/fwprovider/intercept.go b/internal/provider/fwprovider/intercept.go index 78a5a1f997b..a73d3981e19 100644 --- a/internal/provider/fwprovider/intercept.go +++ b/internal/provider/fwprovider/intercept.go @@ -237,6 +237,15 @@ func (w *wrappedDataSource) Configure(ctx context.Context, request datasource.Co w.inner.Configure(ctx, request, response) } +func (w *wrappedDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + if v, ok := w.inner.(datasource.DataSourceWithConfigValidators); ok { + ctx = w.bootstrapContext(ctx, w.meta) + return v.ConfigValidators(ctx) + } + + return nil +} + // tagsDataSourceInterceptor implements transparent tagging for data sources. type tagsDataSourceInterceptor struct { tags *types.ServicePackageResourceTags diff --git a/internal/provider/fwprovider/provider.go b/internal/provider/fwprovider/provider.go index c29a9f9b7d9..f175ebbf31c 100644 --- a/internal/provider/fwprovider/provider.go +++ b/internal/provider/fwprovider/provider.go @@ -337,6 +337,7 @@ func (p *fwprovider) DataSources(ctx context.Context) []func() datasource.DataSo if meta != nil { ctx = tftags.NewContext(ctx, meta.DefaultTagsConfig(ctx), meta.IgnoreTagsConfig(ctx)) ctx = meta.RegisterLogger(ctx) + ctx = flex.RegisterLogger(ctx) } return ctx diff --git a/internal/service/elbv2/generate.go b/internal/service/elbv2/generate.go index 73db5b11c75..97064d40d49 100644 --- a/internal/service/elbv2/generate.go +++ b/internal/service/elbv2/generate.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:generate go run ../../generate/listpages/main.go -ListOps=DescribeListenerCertificates -InputPaginator=Marker -OutputPaginator=NextMarker -- list_listener_certificates_pages_gen.go -//go:generate go run ../../generate/listpages/main.go -ListOps=DescribeRules -InputPaginator=Marker -OutputPaginator=NextMarker -- list_rules_pages_gen.go //go:generate go run ../../generate/tags/main.go -ListTags -ListTagsOp=DescribeTags -ListTagsInIDElem=ResourceArns -ListTagsInIDNeedValueSlice=yes -ListTagsOutTagsElem=TagDescriptions[0].Tags -ServiceTagsSlice -TagOp=AddTags -TagInIDElem=ResourceArns -TagInIDNeedValueSlice=yes -UntagOp=RemoveTags -UpdateTags -CreateTags -KVTValues //go:generate go run ../../generate/servicepackage/main.go //go:generate go run ../../generate/tagstests/main.go diff --git a/internal/service/elbv2/list_rules_pages_gen.go b/internal/service/elbv2/list_rules_pages_gen.go deleted file mode 100644 index 87273ed13d3..00000000000 --- a/internal/service/elbv2/list_rules_pages_gen.go +++ /dev/null @@ -1,27 +0,0 @@ -// Code generated by "internal/generate/listpages/main.go -ListOps=DescribeRules -InputPaginator=Marker -OutputPaginator=NextMarker -- list_rules_pages_gen.go"; DO NOT EDIT. - -package elbv2 - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" -) - -func describeRulesPages(ctx context.Context, conn *elasticloadbalancingv2.Client, input *elasticloadbalancingv2.DescribeRulesInput, fn func(*elasticloadbalancingv2.DescribeRulesOutput, bool) bool) error { - for { - output, err := conn.DescribeRules(ctx, input) - if err != nil { - return err - } - - lastPage := aws.ToString(output.NextMarker) == "" - if !fn(output, lastPage) || lastPage { - break - } - - input.Marker = output.NextMarker - } - return nil -} diff --git a/internal/service/elbv2/listener.go b/internal/service/elbv2/listener.go index 379c360936a..228dbcf97a3 100644 --- a/internal/service/elbv2/listener.go +++ b/internal/service/elbv2/listener.go @@ -4,11 +4,11 @@ package elbv2 import ( + "cmp" "context" "fmt" "log" "slices" - "sort" "strconv" "strings" "time" @@ -572,9 +572,9 @@ func resourceListenerRead(ctx context.Context, d *schema.ResourceData, meta inte if len(listener.Certificates) == 1 { d.Set(names.AttrCertificateARN, listener.Certificates[0].CertificateArn) } - sort.Slice(listener.DefaultActions, func(i, j int) bool { - return aws.ToInt32(listener.DefaultActions[i].Order) < aws.ToInt32(listener.DefaultActions[j].Order) - }) + + sortListenerActions(listener.DefaultActions) + if err := d.Set(names.AttrDefaultAction, flattenListenerActions(d, names.AttrDefaultAction, listener.DefaultActions)); err != nil { return sdkdiag.AppendErrorf(diags, "setting default_action: %s", err) } @@ -1689,3 +1689,9 @@ func diffSuppressMissingForward(attrName string) schema.SchemaDiffSuppressFunc { return false } } + +func sortListenerActions(actions []awstypes.Action) { + slices.SortFunc(actions, func(a, b awstypes.Action) int { + return cmp.Compare(aws.ToInt32(a.Order), aws.ToInt32(b.Order)) + }) +} diff --git a/internal/service/elbv2/listener_data_source.go b/internal/service/elbv2/listener_data_source.go index ee29c35ae2e..f96c3aa4b65 100644 --- a/internal/service/elbv2/listener_data_source.go +++ b/internal/service/elbv2/listener_data_source.go @@ -5,7 +5,6 @@ package elbv2 import ( "context" - "sort" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -334,9 +333,9 @@ func dataSourceListenerRead(ctx context.Context, d *schema.ResourceData, meta in if len(listener.Certificates) == 1 { d.Set(names.AttrCertificateARN, listener.Certificates[0].CertificateArn) } - sort.Slice(listener.DefaultActions, func(i, j int) bool { - return aws.ToInt32(listener.DefaultActions[i].Order) < aws.ToInt32(listener.DefaultActions[j].Order) - }) + + sortListenerActions(listener.DefaultActions) + if err := d.Set(names.AttrDefaultAction, flattenListenerActions(d, names.AttrDefaultAction, listener.DefaultActions)); err != nil { return sdkdiag.AppendErrorf(diags, "setting default_action: %s", err) } diff --git a/internal/service/elbv2/listener_rule.go b/internal/service/elbv2/listener_rule.go index 892d7453054..7d059296ff9 100644 --- a/internal/service/elbv2/listener_rule.go +++ b/internal/service/elbv2/listener_rule.go @@ -9,7 +9,6 @@ import ( "fmt" "log" "slices" - "sort" "strconv" "strings" "time" @@ -47,7 +46,7 @@ const ( // @SDKResource("aws_alb_listener_rule", name="Listener Rule") // @SDKResource("aws_lb_listener_rule", name="Listener Rule") -// @Tags(identifierAttribute="id") +// @Tags(identifierAttribute="arn") // @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types;awstypes;awstypes.Rule") // @Testing(importIgnore="action.0.forward") func resourceListenerRule() *schema.Resource { @@ -578,9 +577,8 @@ 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) - }) + sortListenerActions(rule.Actions) + if err := d.Set(names.AttrAction, flattenListenerActions(d, names.AttrAction, rule.Actions)); err != nil { return sdkdiag.AppendErrorf(diags, "setting action: %s", err) } @@ -765,9 +763,17 @@ func findListenerRule(ctx context.Context, conn *elasticloadbalancingv2.Client, func findListenerRules(ctx context.Context, conn *elasticloadbalancingv2.Client, input *elasticloadbalancingv2.DescribeRulesInput, filter tfslices.Predicate[*awstypes.Rule]) ([]awstypes.Rule, error) { var output []awstypes.Rule - err := describeRulesPages(ctx, conn, input, func(page *elasticloadbalancingv2.DescribeRulesOutput, lastPage bool) bool { - if page == nil { - return !lastPage + paginator := elasticloadbalancingv2.NewDescribeRulesPaginator(conn, input) + for paginator.HasMorePages() { + page, err := paginator.NextPage(ctx) + if errs.IsA[*awstypes.RuleNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + if err != nil { + return nil, err } for _, v := range page.Rules { @@ -775,19 +781,6 @@ func findListenerRules(ctx context.Context, conn *elasticloadbalancingv2.Client, output = append(output, v) } } - - return !lastPage - }) - - if errs.IsA[*awstypes.RuleNotFoundException](err) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if err != nil { - return nil, err } return output, nil @@ -801,6 +794,16 @@ func findListenerRuleByARN(ctx context.Context, conn *elasticloadbalancingv2.Cli return findListenerRule(ctx, conn, input, tfslices.PredicateTrue[*awstypes.Rule]()) } +func findListenerRuleByListenerAndPriority(ctx context.Context, conn *elasticloadbalancingv2.Client, listenerARN, priority string) (*awstypes.Rule, error) { + input := &elasticloadbalancingv2.DescribeRulesInput{ + ListenerArn: aws.String(listenerARN), + } + + return findListenerRule(ctx, conn, input, func(v *awstypes.Rule) bool { + return aws.ToString(v.Priority) == priority + }) +} + func highestListenerRulePriority(ctx context.Context, conn *elasticloadbalancingv2.Client, arn string) (int32, error) { input := &elasticloadbalancingv2.DescribeRulesInput{ ListenerArn: aws.String(arn), @@ -832,15 +835,15 @@ func validListenerRulePriority(v interface{}, k string) (ws []string, errors []e return } -// from arn: -// arn:aws:elasticloadbalancing:us-east-1:012345678912:listener-rule/app/name/0123456789abcdef/abcdef0123456789/456789abcedf1234 -// select submatches: -// (arn:aws:elasticloadbalancing:us-east-1:012345678912:listener)-rule(/app/name/0123456789abcdef/abcdef0123456789)/456789abcedf1234 -// concat to become: -// arn:aws:elasticloadbalancing:us-east-1:012345678912:listener/app/name/0123456789abcdef/abcdef0123456789 -var lbListenerARNFromRuleARNRegexp = regexache.MustCompile(`^(arn:.+:listener)-rule(/.+)/[^/]+$`) - func listenerARNFromRuleARN(ruleARN string) string { + // from arn: + // arn:aws:elasticloadbalancing:us-east-1:012345678912:listener-rule/app/name/0123456789abcdef/abcdef0123456789/456789abcedf1234 + // select submatches: + // (arn:aws:elasticloadbalancing:us-east-1:012345678912:listener)-rule(/app/name/0123456789abcdef/abcdef0123456789)/456789abcedf1234 + // concat to become: + // arn:aws:elasticloadbalancing:us-east-1:012345678912:listener/app/name/0123456789abcdef/abcdef0123456789 + var lbListenerARNFromRuleARNRegexp = regexache.MustCompile(`^(arn:.+:listener)-rule(/.+)/[^/]+$`) + if arnComponents := lbListenerARNFromRuleARNRegexp.FindStringSubmatch(ruleARN); len(arnComponents) > 1 { return arnComponents[1] + arnComponents[2] } diff --git a/internal/service/elbv2/listener_rule_data_source.go b/internal/service/elbv2/listener_rule_data_source.go new file mode 100644 index 00000000000..2b7f2587a14 --- /dev/null +++ b/internal/service/elbv2/listener_rule_data_source.go @@ -0,0 +1,476 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package elbv2 + +import ( + "context" + "fmt" + "strconv" + + "github.com/aws/aws-sdk-go-v2/aws" + awstypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkDataSource("aws_lb_listener_rule", name="Listener Rule") +// @Testing(tagsTest=true) +// @Testing(tagsIdentifierAttribute="arn") +func newDataSourceListenerRule(context.Context) (datasource.DataSourceWithConfigure, error) { + return &dataSourceListenerRule{}, nil +} + +const ( + dsNameListenerRule = "Listener Rule Data Source" +) + +type dataSourceListenerRule struct { + framework.DataSourceWithConfigure +} + +func (d *dataSourceListenerRule) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name + resp.TypeName = "aws_lb_listener_rule" +} + +func (d *dataSourceListenerRule) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrARN: schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + Computed: true, + }, + "listener_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + Computed: true, + }, + names.AttrPriority: schema.Int32Attribute{ + Optional: true, + Computed: true, + }, + names.AttrTags: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + names.AttrAction: schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[actionModel](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "order": schema.Int32Attribute{ + Computed: true, + }, + names.AttrType: schema.StringAttribute{ + Computed: true, + }, + }, + Blocks: map[string]schema.Block{ + "authenticate_cognito": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[authenticateCognitoActionConfigModel](ctx), + Attributes: map[string]schema.Attribute{ + "authentication_request_extra_params": schema.MapAttribute{ + ElementType: types.StringType, + Computed: true, + }, + "on_unauthenticated_request": schema.StringAttribute{ + Computed: true, + }, + names.AttrScope: schema.StringAttribute{ + Computed: true, + }, + "session_cookie_name": schema.StringAttribute{ + Computed: true, + }, + "session_timeout": schema.Int64Attribute{ + Computed: true, + }, + "user_pool_arn": schema.StringAttribute{ + Computed: true, + }, + "user_pool_client_id": schema.StringAttribute{ + Computed: true, + }, + "user_pool_domain": schema.StringAttribute{ + Computed: true, + }, + }, + }, + "authenticate_oidc": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "authentication_request_extra_params": schema.MapAttribute{ + ElementType: types.StringType, + Computed: true, + }, + "authorization_endpoint": schema.StringAttribute{ + Computed: true, + }, + names.AttrClientID: schema.StringAttribute{ + Computed: true, + }, + names.AttrIssuer: schema.StringAttribute{ + Computed: true, + }, + "on_unauthenticated_request": schema.StringAttribute{ + Computed: true, + }, + names.AttrScope: schema.StringAttribute{ + Computed: true, + }, + "session_cookie_name": schema.StringAttribute{ + Computed: true, + }, + "session_timeout": schema.Int64Attribute{ + Computed: true, + }, + "token_endpoint": schema.StringAttribute{ + Computed: true, + }, + "user_info_endpoint": schema.StringAttribute{ + Computed: true, + }, + }, + }, + "fixed_response": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + names.AttrContentType: schema.StringAttribute{ + Computed: true, + }, + "message_body": schema.StringAttribute{ + Computed: true, + }, + names.AttrStatusCode: schema.StringAttribute{ + Computed: true, + }, + }, + }, + "forward": schema.SingleNestedBlock{ + Blocks: map[string]schema.Block{ + "stickiness": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + names.AttrDuration: schema.Int32Attribute{ + Computed: true, + }, + names.AttrEnabled: schema.BoolAttribute{ + Computed: true, + }, + }, + }, + "target_group": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrARN: schema.StringAttribute{ + Computed: true, + }, + names.AttrWeight: schema.Int32Attribute{ + Computed: true, + }, + }, + }, + }, + }, + }, + "redirect": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "host": schema.StringAttribute{ + Computed: true, + }, + names.AttrPath: schema.StringAttribute{ + Computed: true, + }, + names.AttrPort: schema.StringAttribute{ + Computed: true, + }, + names.AttrProtocol: schema.StringAttribute{ + Computed: true, + }, + "query": schema.StringAttribute{ + Computed: true, + }, + names.AttrStatusCode: schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, + }, + }, + names.AttrCondition: schema.SetNestedBlock{ + CustomType: fwtypes.NewSetNestedObjectTypeOf[ruleConditionModel](ctx), + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "host_header": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[hostHeaderConfigModel](ctx), + Attributes: map[string]schema.Attribute{ + names.AttrValues: schema.SetAttribute{ + ElementType: types.StringType, + Computed: true, + }, + }, + }, + "http_header": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[httpHeaderConfigModel](ctx), + Attributes: map[string]schema.Attribute{ + "http_header_name": schema.StringAttribute{ + Computed: true, + }, + names.AttrValues: schema.SetAttribute{ + ElementType: types.StringType, + Computed: true, + }, + }, + }, + "http_request_method": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[httpRquestMethodConfigModel](ctx), + Attributes: map[string]schema.Attribute{ + names.AttrValues: schema.SetAttribute{ + ElementType: types.StringType, + Computed: true, + }, + }, + }, + "path_pattern": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[pathPatternConfigModel](ctx), + Attributes: map[string]schema.Attribute{ + names.AttrValues: schema.SetAttribute{ + ElementType: types.StringType, + Computed: true, + }, + }, + }, + "query_string": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[queryStringConfigModel](ctx), + Blocks: map[string]schema.Block{ + names.AttrValues: schema.SetNestedBlock{ + CustomType: fwtypes.NewSetNestedObjectTypeOf[queryStringKeyValuePairModel](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrKey: schema.StringAttribute{ + Computed: true, + }, + names.AttrValue: schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, + }, + }, + "source_ip": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[pathPatternConfigModel](ctx), + Attributes: map[string]schema.Attribute{ + names.AttrValues: schema.SetAttribute{ + ElementType: types.StringType, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + } +} + +func (d *dataSourceListenerRule) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf( + path.MatchRoot(names.AttrARN), + path.MatchRoot("listener_arn"), + ), + datasourcevalidator.RequiredTogether( + path.MatchRoot("listener_arn"), + path.MatchRoot(names.AttrPriority), + ), + datasourcevalidator.Conflicting( + path.MatchRoot(names.AttrARN), + path.MatchRoot(names.AttrPriority), + ), + } +} + +func (d *dataSourceListenerRule) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + conn := d.Meta().ELBV2Client(ctx) + + var data dataSourceListenerRuleModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + var out *awstypes.Rule + if !data.ARN.IsNull() { + var err error + out, err = findListenerRuleByARN(ctx, conn, data.ARN.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ELBV2, create.ErrActionReading, dsNameListenerRule, data.ARN.String(), err), + err.Error(), + ) + return + } + } else { + var err error + out, err = findListenerRuleByListenerAndPriority(ctx, conn, data.ListenerARN.ValueString(), strconv.Itoa(int(data.Priority.ValueInt32()))) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ELBV2, create.ErrActionReading, dsNameListenerRule, fmt.Sprintf("%s/%s", data.ListenerARN.String(), data.Priority.String()), err), + err.Error(), + ) + return + } + } + + sortListenerActions(out.Actions) + + resp.Diagnostics.Append(flex.Flatten(ctx, out, &data, flex.WithFieldNamePrefix("Rule"))...) + if resp.Diagnostics.HasError() { + return + } + + // The listener arn isn't in the response but can be derived from the rule arn + data.ListenerARN = fwtypes.ARNValue(listenerARNFromRuleARN(aws.ToString(out.RuleArn))) + + priority, err := strconv.ParseInt(aws.ToString(out.Priority), 10, 32) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ELBV2, create.ErrActionReading, dsNameListenerRule, data.ARN.String(), err), + err.Error(), + ) + return + } + data.Priority = types.Int32Value(int32(priority)) + + tags, err := listTags(ctx, conn, aws.ToString(out.RuleArn)) + if err != nil { + resp.Diagnostics.AddError("listing tags for ELBv2 Listener Rule", err.Error()) + return + } + ignoreTagsConfig := d.Meta().IgnoreTagsConfig(ctx) + data.Tags = tftags.FlattenStringValueMap(ctx, tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +type dataSourceListenerRuleModel struct { + Action fwtypes.ListNestedObjectValueOf[actionModel] `tfsdk:"action"` + ARN fwtypes.ARN `tfsdk:"arn"` + Condition fwtypes.SetNestedObjectValueOf[ruleConditionModel] `tfsdk:"condition"` + ListenerARN fwtypes.ARN `tfsdk:"listener_arn"` + Priority types.Int32 `tfsdk:"priority" autoflex:"-"` + Tags tftags.Map `tfsdk:"tags"` +} + +// The API includes a TargetGroupArn field at the root level of the Action. This only applies when Type == "forward" +// and there is a single target group. The read also populates the ForwardConfig with the single TargetGroup, +// so it is redundant. Using the ForwardConfig in all cases improves consistency. +type actionModel struct { + Type types.String `tfsdk:"type"` + AuthenticateCognitoConfig fwtypes.ObjectValueOf[authenticateCognitoActionConfigModel] `tfsdk:"authenticate_cognito"` + AuthenticateOidcConfig fwtypes.ObjectValueOf[authenticateOIDCActionConfigModel] `tfsdk:"authenticate_oidc"` + FixedResponseConfig fwtypes.ObjectValueOf[fixedResponseActionConfigModel] `tfsdk:"fixed_response"` + ForwardConfig fwtypes.ObjectValueOf[forwardActionConfigModel] `tfsdk:"forward"` + Order types.Int32 `tfsdk:"order"` + RedirectConfig fwtypes.ObjectValueOf[redirectActionConfigModel] `tfsdk:"redirect"` +} + +type authenticateCognitoActionConfigModel struct { + AuthenticationRequestExtraParams fwtypes.MapOfString `tfsdk:"authentication_request_extra_params"` + OnUnauthenticatedRequest types.String `tfsdk:"on_unauthenticated_request"` + Scope types.String `tfsdk:"scope"` + SessionCookieName types.String `tfsdk:"session_cookie_name"` + SessionTimeout types.Int64 `tfsdk:"session_timeout"` + UserPoolArn types.String `tfsdk:"user_pool_arn"` + UserPoolClientId types.String `tfsdk:"user_pool_client_id"` + UserPoolDomain types.String `tfsdk:"user_pool_domain"` +} + +type authenticateOIDCActionConfigModel struct { + AuthorizationEndpoint types.String `tfsdk:"authorization_endpoint"` + AuthenticationRequestExtraParams fwtypes.MapOfString `tfsdk:"authentication_request_extra_params"` + ClientId types.String `tfsdk:"client_id"` + Issuer types.String `tfsdk:"issuer"` + OnUnauthenticatedRequest types.String `tfsdk:"on_unauthenticated_request"` + Scope types.String `tfsdk:"scope"` + SessionCookieName types.String `tfsdk:"session_cookie_name"` + SessionTimeout types.Int64 `tfsdk:"session_timeout"` + TokenEndpoint types.String `tfsdk:"token_endpoint"` + UserInfoEndpoint types.String `tfsdk:"user_info_endpoint"` +} + +type fixedResponseActionConfigModel struct { + ContentType types.String `tfsdk:"content_type"` + MessageBody types.String `tfsdk:"message_body"` + StatusCode types.String `tfsdk:"status_code"` +} + +type forwardActionConfigModel struct { + TargetGroupStickinessConfig fwtypes.ObjectValueOf[targetGroupStickinessConfigModel] `tfsdk:"stickiness"` + TargetGroups fwtypes.SetNestedObjectValueOf[targetGroupTupleModel] `tfsdk:"target_group"` +} + +type targetGroupStickinessConfigModel struct { + DurationSeconds types.Int32 `tfsdk:"duration"` + Enabled types.Bool `tfsdk:"enabled"` +} + +type targetGroupTupleModel struct { + TargetGroupArn types.String `tfsdk:"arn"` + Weight types.Int32 `tfsdk:"weight"` +} + +type redirectActionConfigModel struct { + Host types.String `tfsdk:"host"` + Path types.String `tfsdk:"path"` + Port types.String `tfsdk:"port"` + Protocol types.String `tfsdk:"protocol"` + Query types.String `tfsdk:"query"` + StatusCode types.String `tfsdk:"status_code"` +} + +type ruleConditionModel struct { + HostHeaderConfig fwtypes.ObjectValueOf[hostHeaderConfigModel] `tfsdk:"host_header"` + HttpHeaderConfig fwtypes.ObjectValueOf[httpHeaderConfigModel] `tfsdk:"http_header"` + HttpRequestMethodConfig fwtypes.ObjectValueOf[httpRquestMethodConfigModel] `tfsdk:"http_request_method"` + PathPatternConfig fwtypes.ObjectValueOf[pathPatternConfigModel] `tfsdk:"path_pattern"` + QueryStringConfig fwtypes.ObjectValueOf[queryStringConfigModel] `tfsdk:"query_string"` + SourceIpConfig fwtypes.ObjectValueOf[sourceIPConfigModel] `tfsdk:"source_ip"` +} + +type hostHeaderConfigModel struct { + Values fwtypes.SetValueOf[types.String] `tfsdk:"values"` +} + +type httpHeaderConfigModel struct { + HTTPHeaderName types.String `tfsdk:"http_header_name"` + Values fwtypes.SetValueOf[types.String] `tfsdk:"values"` +} + +type httpRquestMethodConfigModel struct { + Values fwtypes.SetValueOf[types.String] `tfsdk:"values"` +} + +type pathPatternConfigModel struct { + Values fwtypes.SetValueOf[types.String] `tfsdk:"values"` +} + +type queryStringConfigModel struct { + Values fwtypes.SetNestedObjectValueOf[queryStringKeyValuePairModel] `tfsdk:"values"` +} + +type queryStringKeyValuePairModel struct { + Key types.String `tfsdk:"key"` + Value types.String `tfsdk:"value"` +} + +type sourceIPConfigModel struct { + Values fwtypes.SetValueOf[types.String] `tfsdk:"values"` +} diff --git a/internal/service/elbv2/listener_rule_data_source_tags_gen_test.go b/internal/service/elbv2/listener_rule_data_source_tags_gen_test.go new file mode 100644 index 00000000000..a0958574d2f --- /dev/null +++ b/internal/service/elbv2/listener_rule_data_source_tags_gen_test.go @@ -0,0 +1,205 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package elbv2_test + +import ( + "context" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/config" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + tfelbv2 "github.com/hashicorp/terraform-provider-aws/internal/service/elbv2" + "github.com/hashicorp/terraform-provider-aws/internal/types" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccELBV2ListenerRuleDataSource_tags(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ListenerRule/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_tags_NullMap(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ListenerRule/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ListenerRule/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ListenerRule/data.tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ListenerRule/data.tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullListenerRuleDataSourceTags(dataSourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_lb_listener_rule.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ListenerRule/data.tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + expectFullListenerRuleDataSourceTags(dataSourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func expectFullListenerRuleDataSourceTags(resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfelbv2.ServicePackage(context.Background()), resourceAddress, &types.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }, knownValue) +} diff --git a/internal/service/elbv2/listener_rule_data_source_test.go b/internal/service/elbv2/listener_rule_data_source_test.go new file mode 100644 index 00000000000..1ff650d9ef7 --- /dev/null +++ b/internal/service/elbv2/listener_rule_data_source_test.go @@ -0,0 +1,1293 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package elbv2_test + +import ( + "fmt" + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" + "github.com/hashicorp/terraform-plugin-testing/compare" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccELBV2ListenerRuleDataSource_byARN(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_byARN(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(dataSourceName, "listener_arn", resourceName, "listener_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrPriority, resourceName, names.AttrPriority), + ), + ConfigStateChecks: []statecheck.StateCheck{ + // action + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "authenticate_cognito": knownvalue.Null(), + "authenticate_oidc": knownvalue.Null(), + "fixed_response": knownvalue.Null(), + "forward": knownvalue.NotNull(), + "order": knownvalue.NotNull(), + "redirect": knownvalue.Null(), + names.AttrType: knownvalue.NotNull(), + }), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + compare.ValuesSame(), + ), + + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward"), knownvalue.ObjectExact(map[string]knownvalue.Check{ + "stickiness": knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrDuration: knownvalue.Null(), + names.AttrEnabled: knownvalue.Bool(false), + }), + "target_group": knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + names.AttrWeight: knownvalue.NotNull(), + }), + }), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward").AtMapKey("target_group").AtSliceIndex(0).AtMapKey(names.AttrARN), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("target_group_arn"), + compare.ValuesSame(), + ), + + // condition + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrCondition), knownvalue.SetExact([]knownvalue.Check{ + expectKnownCondition("host_header", knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("example.com"), + }), + })), + })), + + // tags + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_byListenerAndPriority(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_byListenerAndPriority(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(dataSourceName, "listener_arn", resourceName, "listener_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrPriority, resourceName, names.AttrPriority), + ), + ConfigStateChecks: []statecheck.StateCheck{ + // action + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "authenticate_cognito": knownvalue.Null(), + "authenticate_oidc": knownvalue.Null(), + "fixed_response": knownvalue.Null(), + "forward": knownvalue.NotNull(), + "order": knownvalue.NotNull(), + "redirect": knownvalue.Null(), + names.AttrType: knownvalue.NotNull(), + }), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + compare.ValuesSame(), + ), + + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward"), knownvalue.ObjectExact(map[string]knownvalue.Check{ + "stickiness": knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrDuration: knownvalue.Null(), + names.AttrEnabled: knownvalue.Bool(false), + }), + "target_group": knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + names.AttrWeight: knownvalue.NotNull(), + }), + }), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward").AtMapKey("target_group").AtSliceIndex(0).AtMapKey(names.AttrARN), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("target_group_arn"), + compare.ValuesSame(), + ), + + // condition + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrCondition), knownvalue.SetExact([]knownvalue.Check{ + expectKnownCondition("host_header", knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("example.com"), + }), + })), + })), + + // tags + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_actionAuthenticateCognito(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + dataSourceName := "data.aws_lb_listener_rule.test" + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_actionAuthenticateCognito(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(dataSourceName, "listener_arn", resourceName, "listener_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrPriority, resourceName, names.AttrPriority), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "authenticate_cognito": knownvalue.NotNull(), + "authenticate_oidc": knownvalue.Null(), + "fixed_response": knownvalue.Null(), + "forward": knownvalue.Null(), + "order": knownvalue.NotNull(), + "redirect": knownvalue.Null(), + names.AttrType: knownvalue.NotNull(), + }), + knownvalue.NotNull(), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + compare.ValuesSame(), + ), + + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_cognito"), knownvalue.NotNull()), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_cognito"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_cognito").AtSliceIndex(0), + compare.ValuesSame(), + ), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_actionAuthenticateOIDC(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + dataSourceName := "data.aws_lb_listener_rule.test" + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_actionAuthenticateOIDC(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(dataSourceName, "listener_arn", resourceName, "listener_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrPriority, resourceName, names.AttrPriority), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "authenticate_cognito": knownvalue.Null(), + "authenticate_oidc": knownvalue.NotNull(), + "fixed_response": knownvalue.Null(), + "forward": knownvalue.Null(), + "order": knownvalue.NotNull(), + "redirect": knownvalue.Null(), + names.AttrType: knownvalue.NotNull(), + }), + knownvalue.NotNull(), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + compare.ValuesSame(), + ), + + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc"), knownvalue.NotNull()), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey("authentication_request_extra_params"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey("authentication_request_extra_params"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey("authorization_endpoint"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey("authorization_endpoint"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey(names.AttrClientID), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey(names.AttrClientID), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey(names.AttrIssuer), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey(names.AttrIssuer), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey("on_unauthenticated_request"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey("on_unauthenticated_request"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey(names.AttrScope), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey(names.AttrScope), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey("session_cookie_name"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey("session_cookie_name"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey("session_timeout"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey("session_timeout"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey("token_endpoint"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey("token_endpoint"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtMapKey("user_info_endpoint"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("authenticate_oidc").AtSliceIndex(0).AtMapKey("user_info_endpoint"), + compare.ValuesSame(), + ), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_actionFixedResponse(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_actionFixedResponse(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(dataSourceName, "listener_arn", resourceName, "listener_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrPriority, resourceName, names.AttrPriority), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "authenticate_cognito": knownvalue.Null(), + "authenticate_oidc": knownvalue.Null(), + "fixed_response": knownvalue.NotNull(), + "forward": knownvalue.Null(), + "order": knownvalue.NotNull(), + "redirect": knownvalue.Null(), + names.AttrType: knownvalue.NotNull(), + }), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + compare.ValuesSame(), + ), + + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("fixed_response"), knownvalue.NotNull()), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("fixed_response"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("fixed_response").AtSliceIndex(0), + compare.ValuesSame(), + ), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_actionForwardWeightedStickiness(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_actionForwardWeightedStickiness(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(dataSourceName, "listener_arn", resourceName, "listener_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrPriority, resourceName, names.AttrPriority), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "authenticate_cognito": knownvalue.Null(), + "authenticate_oidc": knownvalue.Null(), + "fixed_response": knownvalue.Null(), + "forward": knownvalue.NotNull(), + "order": knownvalue.NotNull(), + "redirect": knownvalue.Null(), + names.AttrType: knownvalue.NotNull(), + }), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + compare.ValuesSame(), + ), + + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward"), knownvalue.ObjectExact(map[string]knownvalue.Check{ + "stickiness": knownvalue.NotNull(), + "target_group": knownvalue.NotNull(), + })), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward").AtMapKey("stickiness"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward").AtSliceIndex(0).AtMapKey("stickiness").AtSliceIndex(0), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward").AtMapKey("target_group"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("forward").AtSliceIndex(0).AtMapKey("target_group"), + compare.ValuesSame(), + ), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_actionRedirect(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_actionRedirect(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(dataSourceName, "listener_arn", resourceName, "listener_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrPriority, resourceName, names.AttrPriority), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "authenticate_cognito": knownvalue.Null(), + "authenticate_oidc": knownvalue.Null(), + "fixed_response": knownvalue.Null(), + "forward": knownvalue.Null(), + "order": knownvalue.NotNull(), + "redirect": knownvalue.NotNull(), + names.AttrType: knownvalue.NotNull(), + }), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + compare.ValuesSame(), + ), + + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("redirect"), knownvalue.NotNull()), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("redirect"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("redirect").AtSliceIndex(0), + compare.ValuesSame(), + ), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_conditionHostHeader(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_conditionHostHeader(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrCondition), knownvalue.SetExact([]knownvalue.Check{ + expectKnownCondition("host_header", knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("example.com"), + knownvalue.StringExact("www.example.com"), + }), + })), + })), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_conditionHTTPHeader(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_conditionHTTPHeader(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrCondition), knownvalue.SetExact([]knownvalue.Check{ + expectKnownCondition("http_header", knownvalue.ObjectExact(map[string]knownvalue.Check{ + "http_header_name": knownvalue.StringExact("X-Forwarded-For"), + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("192.168.1.*"), + knownvalue.StringExact("10.0.0.*"), + }), + })), + })), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_conditionHTTPRequestMethod(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_conditionHTTPRequestMethod(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrCondition), knownvalue.SetExact([]knownvalue.Check{ + expectKnownCondition("http_request_method", knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("GET"), + knownvalue.StringExact("POST"), + }), + })), + })), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_conditionPathPattern(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_conditionPathPattern(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrCondition), knownvalue.SetExact([]knownvalue.Check{ + expectKnownCondition("path_pattern", knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("/public/*"), + knownvalue.StringExact("/cgi-bin/*"), + }), + })), + })), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_conditionQueryString(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_conditionQueryString(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrCondition), knownvalue.SetExact([]knownvalue.Check{ + expectKnownCondition("query_string", knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrKey: knownvalue.StringExact("one"), + names.AttrValue: knownvalue.StringExact("un"), + }), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrKey: knownvalue.StringExact("two"), + names.AttrValue: knownvalue.StringExact("deux"), + }), + }), + })), + })), + }, + }, + }, + }) +} + +func TestAccELBV2ListenerRuleDataSource_conditionSourceIP(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_conditionSourceIP(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrCondition), knownvalue.SetExact([]knownvalue.Check{ + expectKnownCondition("source_ip", knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("192.168.0.0/16"), + knownvalue.StringExact("dead:cafe::/64"), + }), + })), + })), + }, + }, + }, + }) +} + +func expectKnownCondition(key string, check knownvalue.Check) knownvalue.Check { + checks := map[string]knownvalue.Check{ + "host_header": knownvalue.Null(), + "http_header": knownvalue.Null(), + "http_request_method": knownvalue.Null(), + "path_pattern": knownvalue.Null(), + "query_string": knownvalue.Null(), + "source_ip": knownvalue.Null(), + } + checks[key] = check + return knownvalue.ObjectExact(checks) +} + +func testAccListenerRuleDataSourceConfig_byARN(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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 { + host_header { + values = ["example.com"] + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_byListenerAndPriority(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener_rule.test.listener_arn + priority = aws_lb_listener_rule.test.priority +} + +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 { + host_header { + values = ["example.com"] + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_actionAuthenticateCognito(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), + fmt.Sprintf(` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "authenticate-cognito" + + authenticate_cognito { + user_pool_arn = aws_cognito_user_pool.test.arn + user_pool_client_id = aws_cognito_user_pool_client.test.id + user_pool_domain = aws_cognito_user_pool_domain.test.domain + + authentication_request_extra_params = { + param = "test" + } + } + } + action { + type = "forward" + target_group_arn = aws_lb_target_group.test.arn + } + + condition { + host_header { + values = ["example.com"] + } + } +} + +resource "aws_cognito_user_pool" "test" { + name = %[1]q +} + +resource "aws_cognito_user_pool_client" "test" { + name = %[1]q + user_pool_id = aws_cognito_user_pool.test.id + generate_secret = true + allowed_oauth_flows_user_pool_client = true + allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] + callback_urls = ["https://www.example.com/callback", "https://www.example.com/redirect"] + default_redirect_uri = "https://www.example.com/redirect" + logout_urls = ["https://www.example.com/login"] +} + +resource "aws_cognito_user_pool_domain" "test" { + domain = %[1]q + user_pool_id = aws_cognito_user_pool.test.id +} +`, rName)) +} + +func testAccListenerRuleDataSourceConfig_actionAuthenticateOIDC(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), + fmt.Sprintf(` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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" + target_group_arn = aws_lb_target_group.test.arn + } + + condition { + host_header { + values = ["example.com"] + } + } +} + +resource "aws_cognito_user_pool" "test" { + name = %[1]q +} + +resource "aws_cognito_user_pool_client" "test" { + name = %[1]q + user_pool_id = aws_cognito_user_pool.test.id + generate_secret = true + allowed_oauth_flows_user_pool_client = true + allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] + callback_urls = ["https://www.example.com/callback", "https://www.example.com/redirect"] + default_redirect_uri = "https://www.example.com/redirect" + logout_urls = ["https://www.example.com/login"] +} + +resource "aws_cognito_user_pool_domain" "test" { + domain = %[1]q + user_pool_id = aws_cognito_user_pool.test.id +} +`, rName)) +} + +func testAccListenerRuleDataSourceConfig_actionFixedResponse(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "fixed-response" + + fixed_response { + content_type = "text/plain" + message_body = "Hello" + status_code = "200" + } + } + + condition { + host_header { + values = ["example.com"] + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_actionForwardWeightedStickiness(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigVPCWithSubnets(rName, 2), + fmt.Sprintf(` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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.test1.arn + weight = 1 + } + + target_group { + arn = aws_lb_target_group.test2.arn + weight = 1 + } + + stickiness { + enabled = true + duration = 3600 + } + } + } + + condition { + host_header { + values = ["example.com"] + } + } +} + +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTP" + port = "80" + + default_action { + target_group_arn = aws_lb_target_group.test1.arn + type = "forward" + } +} + +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" + } +} + +resource "aws_security_group" "test" { + name = %[1]q + 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"] + } +} +`, rName[:30])) +} + +func testAccListenerRuleDataSourceConfig_actionRedirect(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "redirect" + + redirect { + port = "443" + protocol = "HTTPS" + query = "param1=value1" + status_code = "HTTP_301" + } + } + + condition { + host_header { + values = ["example.com"] + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_conditionHostHeader(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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 { + host_header { + values = ["example.com", "www.example.com"] + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_conditionHTTPHeader(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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 { + http_header { + http_header_name = "X-Forwarded-For" + values = ["192.168.1.*", "10.0.0.*"] + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_conditionHTTPRequestMethod(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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 { + http_request_method { + values = ["GET", "POST"] + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_conditionPathPattern(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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 = ["/public/*", "/cgi-bin/*"] + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_conditionQueryString(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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 { + query_string { + key = "one" + value = "un" + } + query_string { + key = "two" + value = "deux" + } + } +} +`) +} + +func testAccListenerRuleDataSourceConfig_conditionSourceIP(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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 { + source_ip { + values = [ + "192.168.0.0/16", + "dead:cafe::/64", + ] + } + } +} +`) +} diff --git a/internal/service/elbv2/listener_rule_test.go b/internal/service/elbv2/listener_rule_test.go index 0e9605ece74..b8c3bc8353f 100644 --- a/internal/service/elbv2/listener_rule_test.go +++ b/internal/service/elbv2/listener_rule_test.go @@ -1219,6 +1219,10 @@ func TestAccELBV2ListenerRule_cognito(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "action.0.authenticate_cognito.0.user_pool_domain", cognitoPoolDomainResourceName, names.AttrDomain), resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_cognito.0.authentication_request_extra_params.%", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_cognito.0.authentication_request_extra_params.param", "test"), + resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_cognito.0.on_unauthenticated_request", "authenticate"), + resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_cognito.0.scope", "openid"), + resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_cognito.0.session_cookie_name", "AWSELBAuthSessionCookie"), + resource.TestCheckResourceAttr(resourceName, "action.0.authenticate_cognito.0.session_timeout", "604800"), resource.TestCheckResourceAttr(resourceName, "action.1.order", acctest.Ct2), resource.TestCheckResourceAttr(resourceName, "action.1.type", "forward"), resource.TestCheckResourceAttrPair(resourceName, "action.1.target_group_arn", targetGroupResourceName, names.AttrARN), @@ -2141,7 +2145,7 @@ func testAccCheckListenerRuleExists(ctx context.Context, n string, v *awstypes.R conn := acctest.Provider.Meta().(*conns.AWSClient).ELBV2Client(ctx) - output, err := tfelbv2.FindListenerRuleByARN(ctx, conn, rs.Primary.ID) + output, err := tfelbv2.FindListenerRuleByARN(ctx, conn, rs.Primary.Attributes[names.AttrARN]) if err != nil { return err @@ -2162,7 +2166,7 @@ func testAccCheckListenerRuleDestroy(ctx context.Context) resource.TestCheckFunc continue } - _, err := tfelbv2.FindListenerRuleByARN(ctx, conn, rs.Primary.ID) + _, err := tfelbv2.FindListenerRuleByARN(ctx, conn, rs.Primary.Attributes[names.AttrARN]) if tfresource.NotFound(err) { continue @@ -2172,7 +2176,7 @@ func testAccCheckListenerRuleDestroy(ctx context.Context) resource.TestCheckFunc return err } - return fmt.Errorf("ELBv2 Listener Rule %s still exists", rs.Primary.ID) + return fmt.Errorf("ELBv2 Listener Rule %s still exists", rs.Primary.Attributes[names.AttrARN]) } return nil diff --git a/internal/service/elbv2/service_package_gen.go b/internal/service/elbv2/service_package_gen.go index 0f6c79d96d4..f012ce0f6d1 100644 --- a/internal/service/elbv2/service_package_gen.go +++ b/internal/service/elbv2/service_package_gen.go @@ -15,7 +15,12 @@ import ( type servicePackage struct{} func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.ServicePackageFrameworkDataSource { - return []*types.ServicePackageFrameworkDataSource{} + return []*types.ServicePackageFrameworkDataSource{ + { + Factory: newDataSourceListenerRule, + Name: "Listener Rule", + }, + } } func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { @@ -118,7 +123,7 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka TypeName: "aws_alb_listener_rule", Name: "Listener Rule", Tags: &types.ServicePackageResourceTags{ - IdentifierAttribute: names.AttrID, + IdentifierAttribute: names.AttrARN, }, }, { @@ -160,7 +165,7 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka TypeName: "aws_lb_listener_rule", Name: "Listener Rule", Tags: &types.ServicePackageResourceTags{ - IdentifierAttribute: names.AttrID, + IdentifierAttribute: names.AttrARN, }, }, { diff --git a/internal/service/elbv2/testdata/ListenerRule/data.tags/main_gen.tf b/internal/service/elbv2/testdata/ListenerRule/data.tags/main_gen.tf new file mode 100644 index 00000000000..f4b25a4e14f --- /dev/null +++ b/internal/service/elbv2/testdata/ListenerRule/data.tags/main_gen.tf @@ -0,0 +1,119 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# tflint-ignore: terraform_unused_declarations +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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/*"] + } + } + + tags = var.resource_tags +} + +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTP" + port = "80" + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} + +resource "aws_security_group" "test" { + name = var.rName + 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"] + } +} + +resource "aws_lb" "test" { + name = var.rName + 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" "test" { + name = var.rName + 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" + } +} + +# acctest.ConfigVPCWithSubnets + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/elbv2/testdata/ListenerRule/data.tags_defaults/main_gen.tf b/internal/service/elbv2/testdata/ListenerRule/data.tags_defaults/main_gen.tf new file mode 100644 index 00000000000..8e02e1e5cc5 --- /dev/null +++ b/internal/service/elbv2/testdata/ListenerRule/data.tags_defaults/main_gen.tf @@ -0,0 +1,130 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +# tflint-ignore: terraform_unused_declarations +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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/*"] + } + } + + tags = var.resource_tags +} + +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTP" + port = "80" + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} + +resource "aws_security_group" "test" { + name = var.rName + 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"] + } +} + +resource "aws_lb" "test" { + name = var.rName + 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" "test" { + name = var.rName + 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" + } +} + +# acctest.ConfigVPCWithSubnets + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/elbv2/testdata/ListenerRule/data.tags_ignore/main_gen.tf b/internal/service/elbv2/testdata/ListenerRule/data.tags_ignore/main_gen.tf new file mode 100644 index 00000000000..56ca5214f32 --- /dev/null +++ b/internal/service/elbv2/testdata/ListenerRule/data.tags_ignore/main_gen.tf @@ -0,0 +1,139 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +# tflint-ignore: terraform_unused_declarations +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +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/*"] + } + } + + tags = var.resource_tags +} + +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTP" + port = "80" + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} + +resource "aws_security_group" "test" { + name = var.rName + 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"] + } +} + +resource "aws_lb" "test" { + name = var.rName + 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" "test" { + name = var.rName + 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" + } +} + +# acctest.ConfigVPCWithSubnets + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/elbv2/testdata/tmpl/listener_rule_data_source.gtpl b/internal/service/elbv2/testdata/tmpl/listener_rule_data_source.gtpl new file mode 100644 index 00000000000..1441821740d --- /dev/null +++ b/internal/service/elbv2/testdata/tmpl/listener_rule_data_source.gtpl @@ -0,0 +1,3 @@ +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} diff --git a/skaff/datasource/datasource.go b/skaff/datasource/datasource.go index 5353ea88936..58f2bfb535f 100644 --- a/skaff/datasource/datasource.go +++ b/skaff/datasource/datasource.go @@ -37,6 +37,7 @@ type TemplateData struct { IncludeComments bool IncludeTags bool HumanFriendlyService string + SDKPackage string ServicePackage string Service string ServiceLower string @@ -81,6 +82,7 @@ func Create(dsName, snakeName string, comments, force, v2, pluginFramework, tags HumanFriendlyService: service.HumanFriendly(), IncludeComments: comments, IncludeTags: tags, + SDKPackage: service.GoV2Package(), ServicePackage: servicePackage, Service: service.ProviderNameUpper(), ServiceLower: strings.ToLower(service.ProviderNameUpper()), diff --git a/skaff/datasource/datasource.gtpl b/skaff/datasource/datasource.gtpl index 0ee7324deb9..516838179e6 100644 --- a/skaff/datasource/datasource.gtpl +++ b/skaff/datasource/datasource.gtpl @@ -35,7 +35,7 @@ import ( {{- if and .IncludeComments .AWSGoSDKV2 }} // // Also, AWS Go SDK v2 may handle nested structures differently than v1, - // using the services/{{ .ServicePackage }}/types package. If so, you'll + // using the services/{{ .SDKPackage }}/types package. If so, you'll // need to import types and reference the nested types, e.g., as // types.. {{- end }} @@ -49,11 +49,11 @@ import ( "time" {{ if .AWSGoSDKV2 }} "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}/types" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}/types" {{- else }} "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/{{ .ServicePackage }}" + "github.com/aws/aws-sdk-go/service/{{ .SDKPackage }}" {{- end }} "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" diff --git a/skaff/datasource/datasourcefw.gtpl b/skaff/datasource/datasourcefw.gtpl index 5091cc06ba7..b33cc56288e 100644 --- a/skaff/datasource/datasourcefw.gtpl +++ b/skaff/datasource/datasourcefw.gtpl @@ -34,18 +34,18 @@ import ( {{- if and .IncludeComments .AWSGoSDKV2 }} // // Also, AWS Go SDK v2 may handle nested structures differently than v1, - // using the services/{{ .ServicePackage }}/types package. If so, you'll + // using the services/{{ .SDKPackage }}/types package. If so, you'll // need to import types and reference the nested types, e.g., as // awstypes.. {{- end }} "context" {{ if .AWSGoSDKV2 }} "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}" - awstypes "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}/types" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}" + awstypes "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}/types" {{- else }} "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/{{ .ServicePackage }}" + "github.com/aws/aws-sdk-go/service/{{ .SDKPackage }}" {{- end }} "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" @@ -72,7 +72,7 @@ import ( {{- end }} // Function annotations are used for datasource registration to the Provider. DO NOT EDIT. -// @FrameworkDataSource(name="{{ .HumanDataSourceName }}") +// @SDKDataSource("{{ .ProviderResourceName }}", name="{{ .HumanDataSourceName }}") func newDataSource{{ .DataSource }}(context.Context) (datasource.DataSourceWithConfigure, error) { return &dataSource{{ .DataSource }}{}, nil } @@ -86,7 +86,7 @@ type dataSource{{ .DataSource }} struct { } func (d *dataSource{{ .DataSource }}) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name - resp.TypeName = "aws_{{ .ServicePackage }}_{{ .DataSourceSnake }}" + resp.TypeName = "{{ .ProviderResourceName }}" } {{ if .IncludeComments }} // TIP: ==== SCHEMA ==== diff --git a/skaff/datasource/datasourcetest.gtpl b/skaff/datasource/datasourcetest.gtpl index f5aea172925..cb4372bc95b 100644 --- a/skaff/datasource/datasourcetest.gtpl +++ b/skaff/datasource/datasourcetest.gtpl @@ -35,7 +35,7 @@ import ( {{- if and .IncludeComments .AWSGoSDKV2 }} // // Also, AWS Go SDK v2 may handle nested structures differently than v1, - // using the services/{{ .ServicePackage }}/types package. If so, you'll + // using the services/{{ .SDKPackage }}/types package. If so, you'll // need to import types and reference the nested types, e.g., as // types.. {{- end }} @@ -46,11 +46,11 @@ import ( "github.com/YakDriver/regexache" {{- if .AWSGoSDKV2 }} "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}/types" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}/types" {{- else }} "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/{{ .ServicePackage }}" + "github.com/aws/aws-sdk-go/service/{{ .SDKPackage }}" {{- end }} "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -170,7 +170,7 @@ func TestAcc{{ .Service }}{{ .DataSource }}DataSource_basic(t *testing.T) { t.Skip("skipping long-running test in short mode") } - var {{ .DataSourceLower }} {{ .ServicePackage }}.Describe{{ .DataSource }}Response + var {{ .DataSourceLower }} {{ .SDKPackage }}.Describe{{ .DataSource }}Response rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) dataSourceName := "data.aws_{{ .ServicePackage }}_{{ .DataSourceSnake }}.test" diff --git a/skaff/resource/resource.go b/skaff/resource/resource.go index f8510be55a1..ffeab94d6ca 100644 --- a/skaff/resource/resource.go +++ b/skaff/resource/resource.go @@ -37,6 +37,7 @@ type TemplateData struct { HumanFriendlyService string IncludeComments bool IncludeTags bool + SDKPackage string ServicePackage string Service string ServiceLower string @@ -81,6 +82,7 @@ func Create(resName, snakeName string, comments, force, v2, pluginFramework, tag HumanFriendlyService: service.HumanFriendly(), IncludeComments: comments, IncludeTags: tags, + SDKPackage: service.GoV2Package(), ServicePackage: servicePackage, Service: service.ProviderNameUpper(), ServiceLower: strings.ToLower(service.ProviderNameUpper()), diff --git a/skaff/resource/resource.gtpl b/skaff/resource/resource.gtpl index 4b2aa071dbd..fdade8cfea0 100644 --- a/skaff/resource/resource.gtpl +++ b/skaff/resource/resource.gtpl @@ -35,7 +35,7 @@ import ( {{- if and .IncludeComments .AWSGoSDKV2 }} // // Also, AWS Go SDK v2 may handle nested structures differently than v1, - // using the services/{{ .ServicePackage }}/types package. If so, you'll + // using the services/{{ .SDKPackage }}/types package. If so, you'll // need to import types and reference the nested types, e.g., as // types.. {{- end }} @@ -49,11 +49,11 @@ import ( "time" {{ if .AWSGoSDKV2 }} "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}/types" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}/types" {{- else }} "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/{{ .ServicePackage }}" + "github.com/aws/aws-sdk-go/service/{{ .SDKPackage }}" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" {{- end }} "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -236,7 +236,7 @@ func resource{{ .Resource }}Create(ctx context.Context, d *schema.ResourceData, {{ if .IncludeComments }} // TIP: -- 2. Populate a create input structure {{- end }} - in := &{{ .ServicePackage }}.Create{{ .Resource }}Input{ + in := &{{ .SDKPackage }}.Create{{ .Resource }}Input{ {{- if .IncludeComments }} // TIP: Mandatory or fields that will always be present can be set when // you create the Input structure. (Replace these with real fields.) diff --git a/skaff/resource/resourcefw.gtpl b/skaff/resource/resourcefw.gtpl index 75ba93c4802..282b1aa2c6d 100644 --- a/skaff/resource/resourcefw.gtpl +++ b/skaff/resource/resourcefw.gtpl @@ -34,7 +34,7 @@ import ( {{- if and .IncludeComments .AWSGoSDKV2 }} // // Also, AWS Go SDK v2 may handle nested structures differently than v1, - // using the services/{{ .ServicePackage }}/types package. If so, you'll + // using the services/{{ .SDKPackage }}/types package. If so, you'll // need to import types and reference the nested types, e.g., as // awstypes.. {{- end }} @@ -43,11 +43,11 @@ import ( "time" {{ if .AWSGoSDKV2 }} "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}" - awstypes "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}/types" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}" + awstypes "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}/types" {{- else }} "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/{{ .ServicePackage }}" + "github.com/aws/aws-sdk-go/service/{{ .SDKPackage }}" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" {{- end }} "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" @@ -86,7 +86,7 @@ import ( {{- end }} // Function annotations are used for resource registration to the Provider. DO NOT EDIT. -// @FrameworkResource("aws_{{ .ServicePackage }}_{{ .ResourceSnake }}", name="{{ .HumanResourceName }}") +// @FrameworkResource("{{ .ProviderResourceName }}", name="{{ .HumanResourceName }}") {{- if .IncludeTags }} // @Tags(identifierAttribute="arn") {{- end }} @@ -116,7 +116,7 @@ type resource{{ .Resource }} struct { } func (r *resource{{ .Resource }}) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = "aws_{{ .ServicePackage }}_{{ .ResourceSnake }}" + resp.TypeName = "{{ .ProviderResourceName }}" } {{ if .IncludeComments }} // TIP: ==== SCHEMA ==== @@ -271,7 +271,7 @@ func (r *resource{{ .Resource }}) Create(ctx context.Context, req resource.Creat {{ if .IncludeComments -}} // TIP: -- 3. Populate a Create input structure {{- end }} - var input {{ .ServicePackage }}.Create{{ .Resource }}Input + var input {{ .SDKPackage }}.Create{{ .Resource }}Input {{ if .IncludeComments -}} // TIP: Using a field name prefix allows mapping fields such as `ID` to `{{ .Resource }}Id` {{- end }} @@ -439,7 +439,7 @@ func (r *resource{{ .Resource }}) Update(ctx context.Context, req resource.Updat !plan.ComplexArgument.Equal(state.ComplexArgument) || !plan.Type.Equal(state.Type) { - var input {{ .ServicePackage }}.Update{{ .Resource }}Input + var input {{ .SDKPackage }}.Update{{ .Resource }}Input resp.Diagnostics.Append(flex.Expand(ctx, plan, &input, flex.WithFieldNamePrefix("Test"))...) if resp.Diagnostics.HasError() { return diff --git a/skaff/resource/resourcetest.gtpl b/skaff/resource/resourcetest.gtpl index d2488da1423..c95f1e680a2 100644 --- a/skaff/resource/resourcetest.gtpl +++ b/skaff/resource/resourcetest.gtpl @@ -35,7 +35,7 @@ import ( {{- if and .IncludeComments .AWSGoSDKV2 }} // // Also, AWS Go SDK v2 may handle nested structures differently than v1, - // using the services/{{ .ServicePackage }}/types package. If so, you'll + // using the services/{{ .SDKPackage }}/types package. If so, you'll // need to import types and reference the nested types, e.g., as // types.. {{- end }} @@ -47,11 +47,11 @@ import ( "github.com/YakDriver/regexache" {{- if .AWSGoSDKV2 }} "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}" - "github.com/aws/aws-sdk-go-v2/service/{{ .ServicePackage }}/types" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}" + "github.com/aws/aws-sdk-go-v2/service/{{ .SDKPackage }}/types" {{- else }} "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/{{ .ServicePackage }}" + "github.com/aws/aws-sdk-go/service/{{ .SDKPackage }}" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" {{- end }} sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" @@ -168,7 +168,7 @@ func TestAcc{{ .Service }}{{ .Resource }}_basic(t *testing.T) { t.Skip("skipping long-running test in short mode") } - var {{ .ResourceLower }} {{ .ServicePackage }}.Describe{{ .Resource }}Response + var {{ .ResourceLower }} {{ .SDKPackage }}.Describe{{ .Resource }}Response rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_{{ .ServicePackage }}_{{ .ResourceSnake }}.test" @@ -221,7 +221,7 @@ func TestAcc{{ .Service }}{{ .Resource }}_disappears(t *testing.T) { t.Skip("skipping long-running test in short mode") } - var {{ .ResourceLower }} {{ .ServicePackage }}.Describe{{ .Resource }}Response + var {{ .ResourceLower }} {{ .SDKPackage }}.Describe{{ .Resource }}Response rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_{{ .ServicePackage }}_{{ .ResourceSnake }}.test" @@ -276,16 +276,16 @@ func testAccCheck{{ .Resource }}Destroy(ctx context.Context) resource.TestCheckF continue } - input := &{{ .ServicePackage }}.Describe{{ .Resource }}Input{ + input := &{{ .SDKPackage }}.Describe{{ .Resource }}Input{ {{ .Resource }}Id: aws.String(rs.Primary.ID), } {{- if .AWSGoSDKV2 }} - _, err := conn.Describe{{ .Resource }}(ctx, &{{ .ServicePackage }}.Describe{{ .Resource }}Input{ + _, err := conn.Describe{{ .Resource }}(ctx, &{{ .SDKPackage }}.Describe{{ .Resource }}Input{ {{ .Resource }}Id: aws.String(rs.Primary.ID), }) {{- else }} - _, err := conn.Describe{{ .Resource }}WithContext(ctx, &{{ .ServicePackage }}.Describe{{ .Resource }}Input{ + _, err := conn.Describe{{ .Resource }}WithContext(ctx, &{{ .SDKPackage }}.Describe{{ .Resource }}Input{ {{ .Resource }}Id: aws.String(rs.Primary.ID), }) {{- end }} @@ -294,7 +294,7 @@ func testAccCheck{{ .Resource }}Destroy(ctx context.Context) resource.TestCheckF return nil } {{ else }} - if tfawserr.ErrCodeEquals(err, {{ .ServicePackage }}.ErrCodeNotFoundException) { + if tfawserr.ErrCodeEquals(err, {{ .SDKPackage }}.ErrCodeNotFoundException) { return nil } {{ end -}} @@ -309,7 +309,7 @@ func testAccCheck{{ .Resource }}Destroy(ctx context.Context) resource.TestCheckF } } -func testAccCheck{{ .Resource }}Exists(ctx context.Context, name string, {{ .ResourceLower }} *{{ .ServicePackage }}.Describe{{ .Resource }}Response) resource.TestCheckFunc { +func testAccCheck{{ .Resource }}Exists(ctx context.Context, name string, {{ .ResourceLower }} *{{ .SDKPackage }}.Describe{{ .Resource }}Response) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] if !ok { @@ -323,11 +323,11 @@ func testAccCheck{{ .Resource }}Exists(ctx context.Context, name string, {{ .Res conn := acctest.Provider.Meta().(*conns.AWSClient).{{ .Service }}{{ if .AWSGoSDKV2 }}Client(ctx){{ else }}Conn(ctx){{ end }} {{- if .AWSGoSDKV2 }} - resp, err := conn.Describe{{ .Resource }}(ctx, &{{ .ServicePackage }}.Describe{{ .Resource }}Input{ + resp, err := conn.Describe{{ .Resource }}(ctx, &{{ .SDKPackage }}.Describe{{ .Resource }}Input{ {{ .Resource }}Id: aws.String(rs.Primary.ID), }) {{- else }} - resp, err := conn.Describe{{ .Resource }}WithContext(ctx, &{{ .ServicePackage }}.Describe{{ .Resource }}Input{ + resp, err := conn.Describe{{ .Resource }}WithContext(ctx, &{{ .SDKPackage }}.Describe{{ .Resource }}Input{ {{ .Resource }}Id: aws.String(rs.Primary.ID), }) {{- end }} @@ -345,7 +345,7 @@ func testAccCheck{{ .Resource }}Exists(ctx context.Context, name string, {{ .Res func testAccPreCheck(ctx context.Context, t *testing.T) { conn := acctest.Provider.Meta().(*conns.AWSClient).{{ .Service }}{{ if .AWSGoSDKV2 }}Client(ctx){{ else }}Conn(ctx){{ end }} - input := &{{ .ServicePackage }}.List{{ .Resource }}sInput{} + input := &{{ .SDKPackage }}.List{{ .Resource }}sInput{} {{- if .AWSGoSDKV2 }} _, err := conn.List{{ .Resource }}s(ctx, input) @@ -361,7 +361,7 @@ func testAccPreCheck(ctx context.Context, t *testing.T) { } } -func testAccCheck{{ .Resource }}NotRecreated(before, after *{{ .ServicePackage }}.Describe{{ .Resource }}Response) resource.TestCheckFunc { +func testAccCheck{{ .Resource }}NotRecreated(before, after *{{ .SDKPackage }}.Describe{{ .Resource }}Response) resource.TestCheckFunc { return func(s *terraform.State) error { if before, after := {{ if .AWSGoSDKV2 }}aws.ToString{{ else }}aws.StringValue{{ end }}(before.{{ .Resource }}Id), {{ if .AWSGoSDKV2 }}aws.ToString{{ else }}aws.StringValue{{ end }}(after.{{ .Resource }}Id); before != after { return create.Error(names.{{ .Service }}, create.ErrActionCheckingNotRecreated, tf{{ .ServicePackage }}.ResName{{ .Resource }}, {{ if .AWSGoSDKV2 }}aws.ToString{{ else }}aws.StringValue{{ end }}(before.{{ .Resource }}Id), errors.New("recreated")) diff --git a/website/docs/d/lb_listener_rule.html.markdown b/website/docs/d/lb_listener_rule.html.markdown new file mode 100644 index 00000000000..49d992aa22d --- /dev/null +++ b/website/docs/d/lb_listener_rule.html.markdown @@ -0,0 +1,161 @@ +--- +subcategory: "ELB (Elastic Load Balancing)" +layout: "aws" +page_title: "AWS: aws_lb_listener_rule" +description: |- + Terraform data source for managing an AWS ELB (Elastic Load Balancing) Listener Rule. +--- + +# Data Source: aws_lb_listener_rule + +Provides information about an AWS Elastic Load Balancing Listener Rule. + +## Example Usage + +### Match by Rule ARN + +```terraform +variable "lb_rule_arn" { + type = string +} + +data "aws_lb_listener_rule" "example" { + arn = var.lb_rule_arn +} +``` + +### Match by Listener ARN and Priority + +```terraform +variable "lb_listener_arn" { + type = string +} + +variable "lb_rule_priority" { + type = number +} + +data "aws_lb_listener_rule" "example" { + listener_arn = var.lb_listener_arn + priority = var.lb_rule_priority +} +``` + +## Argument Reference + +This data source supports the following arguments: + +* `arn` - (Optional) ARN of the Listener Rule. + Either `arn` or `listener_arn` must be set. +* `listener_arn` - (Optional) ARN of the associated Listener. + Either `arn` or `listener_arn` must be set. +* `priority` - (Optional) Priority of the Listener Rule within the Listener. + Must be set if `listener_arn` is set, otherwise must not be set. + +## Attribute Reference + +This data source exports the following attributes in addition to the arguments above: + +* `action` - List of actions associated with the rule, sorted by `order`. + [Detailed below](#action). +* `condition` - Set of conditions associated with the rule. + [Detailed below](#condition). +* `tags` - Tags assigned to the Listener Rule. + +### `action` + +* `type` - The type of the action, indicates which sub-block will be populated. +* `order` - The evaluation order of the action. +* `authenticate_cognito` - An action to authenticate using Amazon Cognito. + [Detailed below](#authenticate_cognito). +* `authenticate_oidc` - An action to authenticate using OIDC. + [Detailed below](#authenticate_oidc). +* `fixed_response` - An action to return a fixed response. + [Detailed below](#fixed_response). +* `forward` - An action to forward the request. + [Detailed below](#forward). +* `redirect` - An action to redirect the request. + [Detailed below](#redirect). + +#### `authenticate_cognito` + +* `authentication_request_extra_params` - Set of additional parameters for the request. + [Detailed below](#authentication_request_extra_params). +* `on_unauthenticated_request` - Behavior when the client is not authenticated. +* `scope` - Set of user claims requested. +* `session_cookie_name` - Name of the cookie used to maintain session information. +* `session_timeout` - Maximum duration of the authentication session in seconds. +* `user_pool_arn` - ARN of the Cognito user pool. +* `user_pool_client_id` - ID of the Cognito user pool client. +* `user_pool_domain` - Domain prefix or fully-qualified domain name of the Cognito user pool. + +#### `authenticate_oidc` + +* `authentication_request_extra_params` - Set of additional parameters for the request. + [Detailed below](#authentication_request_extra_params). +* `authorization_endpoint` - The authorization endpoint of the IdP. +* `client_id` - OAuth 2.0 client identifier. +* `issuer` - OIDC issuer identifier of the IdP. +* `on_unauthenticated_request` - Behavior when the client is not authenticated. +* `scope` - Set of user claims requested. +* `session_cookie_name` - Name of the cookie used to maintain session information. +* `session_timeout` - Maximum duration of the authentication session in seconds. +* `token_endpoint` - The token endpoint of the IdP. +* `user_info_endpoint` - The user info endpoint of the IdP. + +#### `authentication_request_extra_params` + +* `key` - Key of query parameter +* `value` - Value of query parameter + +#### `fixed_response` + +* `content_type` - Content type of the response. +* `message_body` - Message body of the response. +* `status_code` - HTTP response code of the response. + +#### `forward` + +* `stickiness` - Target group stickiness for the rule. + [Detailed below](#stickiness). +* `target_group` - Set of target groups for the action. + [Detailed below](#target_group). + +#### `stickiness` + +* `duration` - The time period, in seconds, during which requests from a client should be routed to the same target group. +* `enabled` - Indicates whether target group stickiness is enabled. + +#### `target_group` + +* `arn` - ARN of the target group. +* `weight` - Weight of the target group. + +#### `redirect` + +* `host` - The hostname. +* `path` - The absolute path, starting with `/`. +* `port` - The port. +* `protocol` - The protocol. +* `query` - The query parameters. +* `status_code` - The HTTP redirect code. + +### `condition` + +* `host_header` - Contains a single attribute `values`, which contains a set of host names. +* `http_header` - HTTP header and values to match. + [Detailed below](#http_header). +* `http_request_method` - Contains a single attribute `values`, which contains a set of HTTP request methods. +* `path_pattern` - Contains a single attribute `values`, which contains a set of path patterns to compare against the request URL. +* `query_string` - Query string parameters to match. + [Detailed below](#query_string). +* `source_ip` - Contains a single attribute `values`, which contains a set of source IPs in CIDR notation. + +#### `http_header` + +* `http_header_name` - Name of the HTTP header to match. +* `values` - Set of values to compare against the value of the HTTP header. + +#### `query_string` + +* `values` - Set of `key`-`value` pairs indicating the query string parameters to match. diff --git a/website/docs/r/lb_listener_rule.html.markdown b/website/docs/r/lb_listener_rule.html.markdown index f6f117d7432..d4533cbe96e 100644 --- a/website/docs/r/lb_listener_rule.html.markdown +++ b/website/docs/r/lb_listener_rule.html.markdown @@ -237,7 +237,7 @@ Action Blocks (for `action`) support the following: Forward Blocks (for `forward`) support the following: -* `target_group` - (Required) One or more target groups block. +* `target_group` - (Required) One or more target group blocks. * `stickiness` - (Optional) The target group stickiness for the rule. Target Group Blocks (for `target_group`) supports the following: