Skip to content

Commit

Permalink
resource/cloudflare_ruleset: don't attempt to update the phase for "c…
Browse files Browse the repository at this point in the history
…ustom" rulesets

After creating the base Ruleset, we usually attempt to update it in place
however Rulesets with a "custom" kind don't need this so we can remove it.

Closes #1242
  • Loading branch information
jacobbednarz committed Oct 12, 2021
1 parent 2123dfc commit 1e592b8
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 12 deletions.
3 changes: 3 additions & 0 deletions .changelog/1242.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/cloudflare_ruleset: don't attempt to update "custom" rulesets using the phase entrypoint
```
31 changes: 19 additions & 12 deletions cloudflare/resource_cloudflare_ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,13 @@ func resourceCloudflareRulesetCreate(d *schema.ResourceData, meta interface{}) e
accountID := d.Get("account_id").(string)
zoneID := d.Get("zone_id").(string)

rulesetName := d.Get("name").(string)
rulesetDescription := d.Get("description").(string)
rulesetKind := d.Get("kind").(string)
rs := cloudflare.Ruleset{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Kind: d.Get("kind").(string),
Name: rulesetName,
Description: rulesetDescription,
Kind: rulesetKind,
Phase: d.Get("phase").(string),
}

Expand All @@ -355,22 +358,26 @@ func resourceCloudflareRulesetCreate(d *schema.ResourceData, meta interface{}) e
}

if err != nil {
return errors.Wrap(err, fmt.Sprintf("error creating ruleset %s", d.Get("name").(string)))
return errors.Wrap(err, fmt.Sprintf("error creating ruleset %s", rulesetName))
}

rulesetEntryPoint := cloudflare.Ruleset{
Description: d.Get("description").(string),
Description: rulesetDescription,
Rules: rules,
}

if accountID != "" {
_, err = client.UpdateAccountRulesetPhase(context.Background(), accountID, rs.Phase, rulesetEntryPoint)
} else {
_, err = client.UpdateZoneRulesetPhase(context.Background(), zoneID, rs.Phase, rulesetEntryPoint)
}
// For "custom" rulesets, we don't send a follow up PUT it to the entrypoint
// endpoint.
if rulesetKind != string(cloudflare.RulesetKindCustom) {
if accountID != "" {
_, err = client.UpdateAccountRulesetPhase(context.Background(), accountID, rs.Phase, rulesetEntryPoint)
} else {
_, err = client.UpdateZoneRulesetPhase(context.Background(), zoneID, rs.Phase, rulesetEntryPoint)
}

if err != nil {
return errors.Wrap(err, fmt.Sprintf("error updating ruleset phase entrypoint %s", d.Get("name").(string)))
if err != nil {
return errors.Wrap(err, fmt.Sprintf("error updating ruleset phase entrypoint %s", rulesetName))
}
}

d.SetId(ruleset.ID)
Expand Down
75 changes: 75 additions & 0 deletions cloudflare/resource_cloudflare_ruleset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,45 @@ func TestAccCloudflareRuleset_ActionParametersHTTPDDoSOverride(t *testing.T) {
})
}

func TestAccCloudflareRuleset_AccountLevelCustomWAFRule(t *testing.T) {
// Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the WAF
// service does not yet support the API tokens and it results in
// misleading state error messages.
if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
defer func(apiToken string) {
os.Setenv("CLOUDFLARE_API_TOKEN", apiToken)
}(os.Getenv("CLOUDFLARE_API_TOKEN"))
os.Setenv("CLOUDFLARE_API_TOKEN", "")
}

t.Parallel()
rnd := generateRandomResourceName()
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
zoneName := os.Getenv("CLOUDFLARE_DOMAIN")
resourceName := "cloudflare_ruleset." + rnd

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckCloudflareRulesetAccountLevelCustomWAFRule(rnd, "account level custom rulesets", accountID, zoneName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName+"_account_custom_firewall", "kind", "custom"),
resource.TestCheckResourceAttr(resourceName+"_account_custom_firewall", "phase", "http_request_firewall_custom"),
resource.TestCheckResourceAttr(resourceName+"_account_custom_firewall", "name", "Custom Ruleset for my account"),
resource.TestCheckResourceAttr(resourceName+"_account_custom_firewall", "rules.0.action", "block"),

resource.TestCheckResourceAttr(resourceName+"_account_custom_firewall_root", "kind", "root"),
resource.TestCheckResourceAttr(resourceName+"_account_custom_firewall_root", "phase", "http_request_firewall_custom"),
resource.TestCheckResourceAttr(resourceName+"_account_custom_firewall_root", "name", "Firewall Custom root"),
resource.TestCheckResourceAttr(resourceName+"_account_custom_firewall_root", "rules.0.action", "execute"),
),
},
},
})
}

func testAccCheckCloudflareRulesetMagicTransitSingle(rnd, name, accountID string) string {
return fmt.Sprintf(`
resource "cloudflare_ruleset" "%[1]s" {
Expand Down Expand Up @@ -1515,3 +1554,39 @@ func testAccCheckCloudflareRulesetActionParametersHTTPDDosOverride(rnd, name, zo
}
}`, rnd, name, zoneID, zoneName)
}

func testAccCheckCloudflareRulesetAccountLevelCustomWAFRule(rnd, name, accountID, zoneName string) string {
return fmt.Sprintf(`
resource "cloudflare_ruleset" "%[1]s_account_custom_firewall" {
account_id = "%[3]s"
name = "Custom Ruleset for my account"
description = "example block rule"
kind = "custom"
phase = "http_request_firewall_custom"
rules {
action = "block"
expression = "(http.host eq \"%[4]s\")"
description = "SID"
enabled = true
}
}
resource "cloudflare_ruleset" "%[1]s_account_custom_firewall_root" {
account_id = "%[3]s"
name = "Firewall Custom root"
description = ""
kind = "root"
phase = "http_request_firewall_custom"
rules {
action = "execute"
action_parameters {
id = cloudflare_ruleset.%[1]s_account_custom_firewall.id
}
expression = "(cf.zone.name eq \"example.com\")"
description = ""
enabled = true
}
}`, rnd, name, accountID, zoneName)
}

0 comments on commit 1e592b8

Please sign in to comment.