Skip to content

Commit

Permalink
Extend redirect action with from_value parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis Davydov committed Jul 22, 2022
1 parent 8ae0ac9 commit 4200a88
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .changelog/1781.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/cloudflare_ruleset: add support for `from_value` action parameter when using redirect action
```
25 changes: 25 additions & 0 deletions examples/resources/cloudflare_ruleset/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,28 @@ resource "cloudflare_ruleset" "redirect_from_list_example" {
enabled = true
}
}

# Dynamic Redirects from value resource
resource "cloudflare_ruleset" "redirect_from_value_example" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "redirects"
description = "Redirect ruleset"
kind = "root"
phase = "http_request_dynamic_redirect"

rules {
action = "redirect"
action_parameters {
from_value {
status_code = 301
target_url {
value = "some_host.com"
}
preserve_query_string = true
}
}
expression = "true"
description = "Apply redirect from value"
enabled = true
}
}
36 changes: 35 additions & 1 deletion internal/provider/resource_cloudflare_ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ func buildStateFromRulesetRules(rules []cloudflare.RulesetRule) interface{} {
serveStaleFields []map[string]interface{}
cacheKeyFields []map[string]interface{}
fromListFields []map[string]interface{}
fromValueFields []map[string]interface{}
)
actionParameterRules := make(map[string]string)

Expand Down Expand Up @@ -491,12 +492,23 @@ func buildStateFromRulesetRules(rules []cloudflare.RulesetRule) interface{} {
}

if !reflect.ValueOf(r.ActionParameters.FromList).IsNil() {
fromListFields = append(origin, map[string]interface{}{
fromListFields = append(fromListFields, map[string]interface{}{
"name": r.ActionParameters.FromList.Name,
"key": r.ActionParameters.FromList.Key,
})
}

if !reflect.ValueOf(r.ActionParameters.FromValue).IsNil() {
fromValueFields = append(fromValueFields, map[string]interface{}{
"status_code": r.ActionParameters.FromValue.StatusCode,
"target_url": []interface{}{map[string]interface{}{
"value": r.ActionParameters.FromValue.TargetURL.Value,
"expression": r.ActionParameters.FromValue.TargetURL.Expression,
}},
"preserve_query_string": r.ActionParameters.FromValue.PreserveQueryString,
})
}

actionParameters = append(actionParameters, map[string]interface{}{
"id": r.ActionParameters.ID,
"increment": r.ActionParameters.Increment,
Expand Down Expand Up @@ -524,6 +536,7 @@ func buildStateFromRulesetRules(rules []cloudflare.RulesetRule) interface{} {
"cache_key": cacheKeyFields,
"origin_error_page_passthru": r.ActionParameters.OriginErrorPagePassthru,
"from_list": fromListFields,
"from_value": fromValueFields,
})

rule["action_parameters"] = actionParameters
Expand Down Expand Up @@ -1055,6 +1068,27 @@ func buildRulesetRulesFromResource(d *schema.ResourceData) ([]cloudflare.Ruleset
}
}

case "from_value":
for i := range pValue.([]interface{}) {
var targetURL cloudflare.RulesetRuleActionParametersTargetURL
for _, pValue := range pValue.([]interface{})[i].(map[string]interface{})["target_url"].([]interface{}) {
for pKey, pValue := range pValue.(map[string]interface{}) {
switch pKey {
case "value":
targetURL.Value = pValue.(string)
case "expression":
targetURL.Expression = pValue.(string)
}
}
}

rule.ActionParameters.FromValue = &cloudflare.RulesetRuleActionParametersFromValue{
StatusCode: uint16(pValue.([]interface{})[i].(map[string]interface{})["status_code"].(int)),
TargetURL: targetURL,
PreserveQueryString: pValue.([]interface{})[i].(map[string]interface{})["preserve_query_string"].(bool),
}
}

default:
log.Printf("[DEBUG] unknown key encountered in buildRulesetRulesFromResource for action parameters: %s", pKey)
}
Expand Down
58 changes: 58 additions & 0 deletions internal/provider/resource_cloudflare_ruleset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,37 @@ func TestAccCloudflareRuleset_Redirect(t *testing.T) {
})
}

func TestAccCloudflareRuleset_DynamicRedirect(t *testing.T) {
t.Parallel()
rnd := generateRandomResourceName()
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
resourceName := "cloudflare_ruleset." + rnd

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccCloudflareRulesetRedirectFromValue(rnd, zoneID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", rnd),
resource.TestCheckResourceAttr(resourceName, "kind", "zone"),
resource.TestCheckResourceAttr(resourceName, "phase", "http_request_dynamic_redirect"),

resource.TestCheckResourceAttr(resourceName, "rules.#", "1"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action", "redirect"),

resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.from_value.0.status_code", "301"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.from_value.0.target_url.#", "1"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.from_value.0.target_url.0.expression", ""),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.from_value.0.target_url.0.value", "some_host.com"),
resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.from_value.0.preserve_query_string", "true"),
),
},
},
})
}

func testAccCheckCloudflareRulesetMagicTransitSingle(rnd, name, accountID string) string {
return fmt.Sprintf(`
resource "cloudflare_ruleset" "%[1]s" {
Expand Down Expand Up @@ -2991,3 +3022,30 @@ func testAccCloudflareRulesetRedirectFromList(rnd, accountID string) string {
}
}`, rnd, accountID)
}

func testAccCloudflareRulesetRedirectFromValue(rnd, zoneID string) string {
return fmt.Sprintf(`
resource "cloudflare_ruleset" "%[1]s" {
zone_id = "%[2]s"
name = "%[1]s"
description = "%[1]s ruleset description"
kind = "zone"
phase = "http_request_dynamic_redirect"
rules {
action = "redirect"
action_parameters {
from_value {
status_code = 301
target_url {
value = "some_host.com"
}
preserve_query_string = true
}
}
expression = "true"
description = "Apply redirect from value"
enabled = true
}
}`, rnd, zoneID)
}
40 changes: 40 additions & 0 deletions internal/provider/schema_cloudflare_ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,46 @@ func resourceCloudflareRulesetSchema() map[string]*schema.Schema {
},
},
},
"from_value": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Description: "Use a value to lookup information for the action.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"status_code": {
Type: schema.TypeInt,
Description: "Status code for redirect.",
Optional: true,
},
"target_url": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Description: "Target URL for redirect.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"value": {
Type: schema.TypeString,
Optional: true,
Description: "Static value to provide as the HTTP request header value. Conflicts with `\"expression\"`.",
},
"expression": {
Description: "Use a value dynamically determined by the Firewall Rules expression language based on Wireshark display filters. Refer to the [Firewall Rules language](https://developers.cloudflare.com/firewall/cf-firewall-language) documentation for all available fields, operators, and functions. Conflicts with `\"value\"`.",
Type: schema.TypeString,
Optional: true,
},
},
},
},
"preserve_query_string": {
Type: schema.TypeBool,
Description: "Preserve query string for redirect URL.",
Optional: true,
},
},
},
},
},
},
},
Expand Down

0 comments on commit 4200a88

Please sign in to comment.