diff --git a/.changelog/44702.txt b/.changelog/44702.txt new file mode 100644 index 000000000000..493d4c188a50 --- /dev/null +++ b/.changelog/44702.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_lb_listener_rule: Add `transform` configuration block +``` + +```release-note:enhancement +data-source/aws_lb_listener_rule: Add `transform` attribute +``` diff --git a/internal/service/elbv2/listener_rule.go b/internal/service/elbv2/listener_rule.go index e51fff04dbe9..58f6918aa5d4 100644 --- a/internal/service/elbv2/listener_rule.go +++ b/internal/service/elbv2/listener_rule.go @@ -486,6 +486,40 @@ func resourceListenerRule() *schema.Resource { }, names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), + "transform": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 2, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrType: { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[awstypes.TransformTypeEnum](), + }, + "host_header_rewrite_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rewrite": transformRewriteConfigSchema(), + }, + }, + }, + "url_rewrite_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rewrite": transformRewriteConfigSchema(), + }, + }, + }, + }, + }, + }, }, CustomizeDiff: customdiff.All( @@ -494,6 +528,28 @@ func resourceListenerRule() *schema.Resource { } } +func transformRewriteConfigSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, // This argument is an array, but the current AWS API accepts exactly only one `rewrite` + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "regex": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "replace": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 1024), + }, + }, + }, + } +} + func suppressIfActionTypeNot(t awstypes.ActionTypeEnum) schema.SchemaDiffSuppressFunc { return func(k, old, new string, d *schema.ResourceData) bool { take := 2 @@ -531,6 +587,10 @@ func resourceListenerRuleCreate(ctx context.Context, d *schema.ResourceData, met return sdkdiag.AppendFromErr(diags, err) } + if v, ok := d.GetOk("transform"); ok && len(v.(*schema.Set).List()) > 0 { + input.Transforms = expandRuleTransforms(v.(*schema.Set).List()) + } + output, err := retryListenerRuleCreate(ctx, conn, d, input, listenerARN) // Some partitions (e.g. ISO) may not support tag-on-create. @@ -648,6 +708,10 @@ func resourceListenerRuleRead(ctx context.Context, d *schema.ResourceData, meta return sdkdiag.AppendErrorf(diags, "setting condition: %s", err) } + if err := d.Set("transform", flattenRuleTransforms(rule.Transforms)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting transform: %s", err) + } + return diags } @@ -695,6 +759,15 @@ func resourceListenerRuleUpdate(ctx context.Context, d *schema.ResourceData, met requestUpdate = true } + if d.HasChange("transform") { + if v, ok := d.GetOk("transform"); ok && len(v.(*schema.Set).List()) > 0 { + input.Transforms = expandRuleTransforms(d.Get("transform").(*schema.Set).List()) + } else { + input.ResetTransforms = aws.Bool(true) + } + requestUpdate = true + } + if requestUpdate { resp, err := conn.ModifyRule(ctx, input) if err != nil { @@ -993,6 +1066,74 @@ func expandPathPatternConditionConfig(tfMap map[string]any) *awstypes.PathPatter return apiObject } +func expandRuleTransforms(tfList []any) []awstypes.RuleTransform { + var apiObjects []awstypes.RuleTransform + + for _, tfMapRaw := range tfList { + if tfMapRaw == nil { + continue + } + tfMap := tfMapRaw.(map[string]any) + apiObject := awstypes.RuleTransform{} + + if v, ok := tfMap[names.AttrType]; ok && v.(string) != "" { + apiObject.Type = awstypes.TransformTypeEnum(v.(string)) + } + if v, ok := tfMap["host_header_rewrite_config"].([]any); ok && len(v) > 0 { + apiObject.HostHeaderRewriteConfig = expandHostHeaderRewriteConfig(v[0].(map[string]any)) + } + if v, ok := tfMap["url_rewrite_config"].([]any); ok && len(v) > 0 { + apiObject.UrlRewriteConfig = expandURLRewriteConfig(v[0].(map[string]any)) + } + apiObjects = append(apiObjects, apiObject) + } + return apiObjects +} + +func expandHostHeaderRewriteConfig(tfMap map[string]any) *awstypes.HostHeaderRewriteConfig { + if tfMap == nil { + return &awstypes.HostHeaderRewriteConfig{} + } + + apiObject := &awstypes.HostHeaderRewriteConfig{} + if v, ok := tfMap["rewrite"].([]any); ok && len(v) > 0 { + apiObject.Rewrites = expandRewriteConfig(v) + } + return apiObject +} + +func expandURLRewriteConfig(tfMap map[string]any) *awstypes.UrlRewriteConfig { + if tfMap == nil { + return &awstypes.UrlRewriteConfig{} + } + + apiObject := &awstypes.UrlRewriteConfig{} + if v, ok := tfMap["rewrite"].([]any); ok && len(v) > 0 { + apiObject.Rewrites = expandRewriteConfig(v) + } + return apiObject +} + +func expandRewriteConfig(tfList []any) []awstypes.RewriteConfig { + if len(tfList) == 0 { + return nil + } + var apiObjects []awstypes.RewriteConfig + + for _, tfMapRaw := range tfList { + if tfMapRaw == nil { + continue + } + tfMap := tfMapRaw.(map[string]any) + apiObject := awstypes.RewriteConfig{ + Regex: aws.String(tfMap["regex"].(string)), + Replace: aws.String(tfMap["replace"].(string)), + } + apiObjects = append(apiObjects, apiObject) + } + return apiObjects +} + func flattenHostHeaderConditionConfig(apiObject *awstypes.HostHeaderConditionConfig) map[string]any { if apiObject == nil { return nil @@ -1039,3 +1180,66 @@ func flattenPathPatternConditionConfig(apiObject *awstypes.PathPatternConditionC } return tfMap } + +func flattenRuleTransforms(apiObjects []awstypes.RuleTransform) []any { + if len(apiObjects) == 0 { + return nil + } + var tfList []any + + for _, apiObject := range apiObjects { + tfMap := make(map[string]any) + + if v := string(apiObject.Type); v != "" { + tfMap[names.AttrType] = v + } + if v := flattenHostHeaderRewriteConfig(apiObject.HostHeaderRewriteConfig); v != nil { + tfMap["host_header_rewrite_config"] = []any{v} + } + if v := flattenURLRewriteConfig(apiObject.UrlRewriteConfig); v != nil { + tfMap["url_rewrite_config"] = []any{v} + } + tfList = append(tfList, tfMap) + } + return tfList +} + +func flattenHostHeaderRewriteConfig(apiObject *awstypes.HostHeaderRewriteConfig) map[string]any { + if apiObject == nil { + return nil + } + tfMap := make(map[string]any) + + if v := flattenRewriteConfig(apiObject.Rewrites); v != nil { + tfMap["rewrite"] = v + } + return tfMap +} + +func flattenURLRewriteConfig(apiObject *awstypes.UrlRewriteConfig) map[string]any { + if apiObject == nil { + return nil + } + tfMap := make(map[string]any) + + if v := flattenRewriteConfig(apiObject.Rewrites); v != nil { + tfMap["rewrite"] = v + } + return tfMap +} + +func flattenRewriteConfig(apiObjects []awstypes.RewriteConfig) []any { + if len(apiObjects) == 0 { + return nil + } + var tfList []any + + for _, apiObject := range apiObjects { + tfMap := map[string]any{ + "regex": aws.ToString(apiObject.Regex), + "replace": aws.ToString(apiObject.Replace), + } + tfList = append(tfList, tfMap) + } + return tfList +} diff --git a/internal/service/elbv2/listener_rule_data_source.go b/internal/service/elbv2/listener_rule_data_source.go index 3974d4a46411..a49ac76f511f 100644 --- a/internal/service/elbv2/listener_rule_data_source.go +++ b/internal/service/elbv2/listener_rule_data_source.go @@ -313,6 +313,50 @@ func (d *listenerRuleDataSource) Schema(ctx context.Context, req datasource.Sche }, }, }, + "transform": schema.SetNestedBlock{ + CustomType: fwtypes.NewSetNestedObjectTypeOf[transformModel](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrType: schema.StringAttribute{ + Computed: true, + }, + }, + Blocks: map[string]schema.Block{ + "host_header_rewrite_config": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[hostHeaderRewriteConfigModel](ctx), + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "rewrite": transformRewriteConfigDataSourceSchema(ctx), + }, + }, + }, + "url_rewrite_config": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[urlRewriteConfigModel](ctx), + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "rewrite": transformRewriteConfigDataSourceSchema(ctx), + }, + }, + }, + }, + }, + }, + }, + } +} + +func transformRewriteConfigDataSourceSchema(ctx context.Context) schema.Block { + return schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[rewriteConfigModel](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "regex": schema.StringAttribute{ + Computed: true, + }, + "replace": schema.StringAttribute{ + Computed: true, + }, + }, }, } } @@ -397,6 +441,7 @@ type listenerRuleDataSourceModel struct { ListenerARN fwtypes.ARN `tfsdk:"listener_arn"` Priority types.Int32 `tfsdk:"priority" autoflex:"-"` Tags tftags.Map `tfsdk:"tags"` + Transform fwtypes.SetNestedObjectValueOf[transformModel] `tfsdk:"transform"` } // The API includes a TargetGroupArn field at the root level of the Action. This only applies when Type == "forward" @@ -507,3 +552,22 @@ type queryStringKeyValuePairModel struct { type sourceIPConfigModel struct { Values fwtypes.SetValueOf[types.String] `tfsdk:"values"` } + +type transformModel struct { + Type types.String `tfsdk:"type"` + HostHeaderRewriteConfig fwtypes.ListNestedObjectValueOf[hostHeaderRewriteConfigModel] `tfsdk:"host_header_rewrite_config"` + URLRewriteConfig fwtypes.ListNestedObjectValueOf[urlRewriteConfigModel] `tfsdk:"url_rewrite_config"` +} + +type hostHeaderRewriteConfigModel struct { + Rewrites fwtypes.ListNestedObjectValueOf[rewriteConfigModel] `tfsdk:"rewrite"` +} + +type urlRewriteConfigModel struct { + Rewrites fwtypes.ListNestedObjectValueOf[rewriteConfigModel] `tfsdk:"rewrite"` +} + +type rewriteConfigModel struct { + Regex types.String `tfsdk:"regex"` + Replace types.String `tfsdk:"replace"` +} diff --git a/internal/service/elbv2/listener_rule_data_source_test.go b/internal/service/elbv2/listener_rule_data_source_test.go index c9986317b19d..b30adb5c2c68 100644 --- a/internal/service/elbv2/listener_rule_data_source_test.go +++ b/internal/service/elbv2/listener_rule_data_source_test.go @@ -921,6 +921,64 @@ func TestAccELBV2ListenerRuleDataSource_conditionSourceIP(t *testing.T) { }) } +func TestAccELBV2ListenerRuleDataSource_transform(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_transform(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New("transform"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrType: knownvalue.StringExact(string(awstypes.TransformTypeEnumHostHeaderRewrite)), + "host_header_rewrite_config": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "rewrite": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "regex": knownvalue.StringExact("^mywebsite-(.+).com$"), + "replace": knownvalue.StringExact("internal.dev.$1.myweb.com"), + }), + }), + }), + }), + "url_rewrite_config": knownvalue.ListExact([]knownvalue.Check{}), + }), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrType: knownvalue.StringExact(string(awstypes.TransformTypeEnumUrlRewrite)), + "host_header_rewrite_config": knownvalue.ListExact([]knownvalue.Check{}), + "url_rewrite_config": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "rewrite": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "regex": knownvalue.StringExact("^/dp/([A-Za-z0-9]+)/?$"), + "replace": knownvalue.StringExact("/product.php?id=$1"), + }), + }), + }), + }), + }), + })), + }, + }, + }, + }) +} + func expectKnownCondition(key string, check knownvalue.Check) knownvalue.Check { checks := map[string]knownvalue.Check{ "host_header": knownvalue.ListExact([]knownvalue.Check{}), @@ -1508,3 +1566,46 @@ resource "aws_lb_listener_rule" "test" { } `) } + +func testAccListenerRuleDataSourceConfig_transform(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 + + action { + type = "forward" + target_group_arn = aws_lb_target_group.test.arn + } + + condition { + path_pattern { + values = ["*"] + } + } + + transform { + type = "host-header-rewrite" + host_header_rewrite_config { + rewrite { + regex = "^mywebsite-(.+).com$" + replace = "internal.dev.$1.myweb.com" + } + } + } + + transform { + type = "url-rewrite" + url_rewrite_config { + rewrite { + regex = "^/dp/([A-Za-z0-9]+)/?$" + replace = "/product.php?id=$1" + } + } + } +} +`) +} diff --git a/internal/service/elbv2/listener_rule_test.go b/internal/service/elbv2/listener_rule_test.go index 76cbe995e26c..a5d9d3425a20 100644 --- a/internal/service/elbv2/listener_rule_test.go +++ b/internal/service/elbv2/listener_rule_test.go @@ -2227,6 +2227,86 @@ func TestAccELBV2ListenerRule_conditionUpdateMultiple(t *testing.T) { }) } +func TestAccELBV2ListenerRule_transform(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + 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: testAccListenerRuleConfig_transform(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "transform.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "transform.*", map[string]string{ + names.AttrType: string(awstypes.TransformTypeEnumHostHeaderRewrite), + "host_header_rewrite_config.#": "1", + "host_header_rewrite_config.0.rewrite.#": "1", + "host_header_rewrite_config.0.rewrite.0.regex": "^mywebsite-(.+).com$", + "host_header_rewrite_config.0.rewrite.0.replace": "internal.dev.$1.myweb.com", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "transform.*", map[string]string{ + names.AttrType: string(awstypes.TransformTypeEnumUrlRewrite), + "url_rewrite_config.#": "1", + "url_rewrite_config.0.rewrite.#": "1", + "url_rewrite_config.0.rewrite.0.regex": "^/dp/([A-Za-z0-9]+)/?$", + "url_rewrite_config.0.rewrite.0.replace": "/product.php?id=$1", + }), + ), + }, + { + Config: testAccListenerRuleConfig_transformUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "transform.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "transform.*", map[string]string{ + names.AttrType: string(awstypes.TransformTypeEnumHostHeaderRewrite), + "host_header_rewrite_config.#": "1", + "host_header_rewrite_config.0.rewrite.#": "1", + "host_header_rewrite_config.0.rewrite.0.regex": "^mywebsite2-(.+).com$", + "host_header_rewrite_config.0.rewrite.0.replace": "internal.dev.$1.myweb.com", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "transform.*", map[string]string{ + names.AttrType: string(awstypes.TransformTypeEnumUrlRewrite), + "url_rewrite_config.#": "1", + "url_rewrite_config.0.rewrite.#": "1", + "url_rewrite_config.0.rewrite.0.regex": "^/dp2/([A-Za-z0-9]+)/?$", + "url_rewrite_config.0.rewrite.0.replace": "/product.php?id=$1", + }), + ), + }, + { + Config: testAccListenerRuleConfig_transformRemoveOneEntry(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "transform.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "transform.*", map[string]string{ + names.AttrType: string(awstypes.TransformTypeEnumUrlRewrite), + "url_rewrite_config.#": "1", + "url_rewrite_config.0.rewrite.#": "1", + "url_rewrite_config.0.rewrite.0.regex": "^/dp2/([A-Za-z0-9]+)/?$", + "url_rewrite_config.0.rewrite.0.replace": "/product.php?id=$1", + }), + ), + }, + { + // Remove all transforms + Config: testAccListenerRuleConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "transform.#", "0"), + ), + }, + }, + }) +} + func testAccCheckListenerRuleActionOrderDisappears(ctx context.Context, rule *awstypes.Rule, actionOrderToDelete int) resource.TestCheckFunc { return func(s *terraform.State) error { var newActions []awstypes.Action @@ -4892,3 +4972,113 @@ condition { } `, lbName) } + +func testAccListenerRuleConfig_transform(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +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/*"] + } + } + + transform { + type = "host-header-rewrite" + host_header_rewrite_config { + rewrite { + regex = "^mywebsite-(.+).com$" + replace = "internal.dev.$1.myweb.com" + } + } + } + + transform { + type = "url-rewrite" + url_rewrite_config { + rewrite { + regex = "^/dp/([A-Za-z0-9]+)/?$" + replace = "/product.php?id=$1" + } + } + } +} +`) +} + +func testAccListenerRuleConfig_transformUpdated(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +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/*"] + } + } + + transform { + type = "url-rewrite" + url_rewrite_config { + rewrite { + regex = "^/dp2/([A-Za-z0-9]+)/?$" + replace = "/product.php?id=$1" + } + } + } + + transform { + type = "host-header-rewrite" + host_header_rewrite_config { + rewrite { + regex = "^mywebsite2-(.+).com$" + replace = "internal.dev.$1.myweb.com" + } + } + } +} +`) +} + +func testAccListenerRuleConfig_transformRemoveOneEntry(rName string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` +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/*"] + } + } + + transform { + type = "url-rewrite" + url_rewrite_config { + rewrite { + regex = "^/dp2/([A-Za-z0-9]+)/?$" + replace = "/product.php?id=$1" + } + } + } +} +`) +} diff --git a/website/docs/d/lb_listener_rule.html.markdown b/website/docs/d/lb_listener_rule.html.markdown index 7c4428da4c8b..0a7e05573313 100644 --- a/website/docs/d/lb_listener_rule.html.markdown +++ b/website/docs/d/lb_listener_rule.html.markdown @@ -62,6 +62,7 @@ This data source exports the following attributes in addition to the arguments a * `condition` - Set of conditions associated with the rule. [Detailed below](#condition). * `tags` - Tags assigned to the Listener Rule. +* `transform` - Block for transform to apply to requests that match this rule. [Detailed below](#transform). ### `action` @@ -173,3 +174,22 @@ This data source exports the following attributes in addition to the arguments a #### `query_string` * `values` - Set of `key`-`value` pairs indicating the query string parameters to match. + +### `transform` + +* `type` - Type of transform. +* `host_header_rewrite_config` - Block for host header rewrite. [Detailed below](#host_header_rewrite_config). +* `url_rewrite_config` - Block for URL rewrite. [Detailed below](#url_rewrite_config). + +#### `host_header_rewrite_config` + +* `rewrite` - Block for host header rewrite configuration. [Detailed below](#rewrite). + +#### `url_rewrite_config` + +* `rewrite` - Block for URL rewrite configuration. [Detailed below](#rewrite). + +#### `rewrite` + +* `regex` - Regular expression to match in the input string. +* `replace` - Replacement string to use when rewriting the matched input. diff --git a/website/docs/r/lb_listener_rule.html.markdown b/website/docs/r/lb_listener_rule.html.markdown index 262b599cea3a..bea63266cdf1 100644 --- a/website/docs/r/lb_listener_rule.html.markdown +++ b/website/docs/r/lb_listener_rule.html.markdown @@ -202,6 +202,43 @@ resource "aws_lb_listener_rule" "oidc" { target_group_arn = aws_lb_target_group.static.arn } } + +# With transform + +resource "aws_lb_listener_rule" "transform" { + listener_arn = aws_lb_listener.front_end.arn + + action { + type = "forward" + target_group_arn = aws_lb_target_group.static.arn + } + + condition { + path_pattern { + values = ["*"] + } + } + + transform { + type = "host-header-rewrite" + host_header_rewrite_config { + rewrite { + regex = "^mywebsite-(.+).com$" + replace = "internal.dev.$1.myweb.com" + } + } + } + + transform { + type = "url-rewrite" + url_rewrite_config { + rewrite { + regex = "^/dp/([A-Za-z0-9]+)/?$" + replace = "/product.php?id=$1" + } + } + } +} ``` ## Argument Reference @@ -214,6 +251,7 @@ This resource supports the following arguments: * `action` - (Required) An Action block. Action blocks are documented below. * `condition` - (Required) A Condition block. Multiple condition blocks of different types can be set and all must be satisfied for the rule to match. Condition blocks are documented below. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `transform` - (Optional) Configuration block that defines the transform to apply to requests matching this rule. See [Transform Blocks](#transform-blocks) below for more details. Once specified, to remove the transform from the rule, remove the `transform` block from the configuration. ### Action Blocks @@ -346,6 +384,33 @@ Query String Value Blocks (for `query_string.values`) support the following: * `key` - (Optional) Query string key pattern to match. * `value` - (Required) Query string value pattern to match. +#### Transform Blocks + +Transform Blocks (for `transform`) support the following: + +* `type` - (Required) Type of transform. Valid values are `host-header-rewrite` and `url-rewrite`. +* `host_header_rewrite_config` - (Optional) Configuration block for host header rewrite. Required if `type` is `host-header-rewrite`. See [Host Header Rewrite Config Blocks](#host-header-rewrite-config-blocks) below. +* `url_rewrite_config` - (Optional) Configuration block for URL rewrite. Required if `type` is `url-rewrite`. See [URL Rewrite Config Blocks](#url-rewrite-config-blocks) below. + +### Host Header Rewrite Config Blocks + +Host Header Rewrite Config Blocks (for `host_header_rewrite_config`) support the following: + +* `rewrite` - (Optional) Block for host header rewrite configuration. Only one block is accepted. See [Rewrite Blocks](#rewrite-blocks) below. + +### URL Rewrite Config Blocks + +URL Rewrite Config Blocks (for `url_rewrite_config`) support the following: + +* `rewrite` - (Optional) Block for URL rewrite configuration. Only one block is accepted. See [Rewrite Blocks](#rewrite-blocks) below. + +### Rewrite Blocks + +Rewrite Blocks (for `rewrite`) support the following: + +* `regex` - (Required) Regular expression to match in the input string. Length constraints: Between 1 and 1024 characters. +* `replace` - (Required) Replacement string to use when rewriting the matched input. Capture groups in the regular expression (for example, `$1` and `$2`) can be specified. Length constraints: Between 0 and 1024 characters. + ## Attribute Reference This resource exports the following attributes in addition to the arguments above: